diff --git a/api/current.xml b/api/current.xml index 8cd368f3519fa..cd200c143d681 100644 --- a/api/current.xml +++ b/api/current.xml @@ -20148,6 +20148,34 @@ visibility="public" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to receive + * this broadcast. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PASSWORD_CHANGED @@ -94,6 +98,10 @@ public class DeviceAdmin extends BroadcastReceiver { * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts() * DevicePolicyManager.getCurrentFailedPasswordAttempts()}. You will generally * handle this in {@link DeviceAdmin#onPasswordFailed(Context, Intent)}. + * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive + * this broadcast. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PASSWORD_FAILED @@ -102,6 +110,10 @@ public class DeviceAdmin extends BroadcastReceiver { /** * Action sent to a device administrator when the user has successfully * entered their password, after failing one or more times. + * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive + * this broadcast. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PASSWORD_SUCCEEDED diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java index eac6e46a809b4..92fdbc80908f0 100644 --- a/core/java/android/app/DeviceAdminInfo.java +++ b/core/java/android/app/DeviceAdminInfo.java @@ -19,21 +19,28 @@ package android.app; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.R; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.content.res.Resources.NotFoundException; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; +import android.util.Log; import android.util.Printer; +import android.util.SparseArray; import android.util.Xml; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; /** * This class is used to specify meta information of a device administrator @@ -42,11 +49,123 @@ import java.io.IOException; public final class DeviceAdminInfo implements Parcelable { static final String TAG = "DeviceAdminInfo"; + /** + * A type of policy that this device admin can use: limit the passwords + * that the user can select, via {@link DevicePolicyManager#setPasswordMode} + * and {@link DevicePolicyManager#setMinimumPasswordLength}. + * + *

To control this policy, the device admin must have a "limit-password" + * tag in the "uses-policies" section of its meta-data. + */ + public static final int USES_POLICY_LIMIT_PASSWORD = 0; + + /** + * A type of policy that this device admin can use: able to watch login + * attempts from the user, via {@link DeviceAdmin#ACTION_PASSWORD_FAILED}, + * {@link DeviceAdmin#ACTION_PASSWORD_SUCCEEDED}, and + * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts}. + * + *

To control this policy, the device admin must have a "watch-login" + * tag in the "uses-policies" section of its meta-data. + */ + public static final int USES_POLICY_WATCH_LOGIN = 1; + + /** + * A type of policy that this device admin can use: able to reset the + * user's password via + * {@link DevicePolicyManager#resetPassword}. + * + *

To control this policy, the device admin must have a "reset-password" + * tag in the "uses-policies" section of its meta-data. + */ + public static final int USES_POLICY_RESET_PASSWORD = 2; + + /** + * A type of policy that this device admin can use: able to limit the + * maximum lock timeout for the device via + * {@link DevicePolicyManager#setMaximumTimeToLock}. + * + *

To control this policy, the device admin must have a "limit-unlock" + * tag in the "uses-policies" section of its meta-data. + */ + public static final int USES_POLICY_LIMIT_UNLOCK = 3; + + /** + * A type of policy that this device admin can use: able to force the device + * to lock via{@link DevicePolicyManager#lockNow}. + * + *

To control this policy, the device admin must have a "force-lock" + * tag in the "uses-policies" section of its meta-data. + */ + public static final int USES_POLICY_FORCE_LOCK = 4; + + /** + * A type of policy that this device admin can use: able to factory + * reset the device, erasing all of the user's data, via + * {@link DevicePolicyManager#wipeData}. + * + *

To control this policy, the device admin must have a "wipe-data" + * tag in the "uses-policies" section of its meta-data. + */ + public static final int USES_POLICY_WIPE_DATA = 5; + + /** @hide */ + public static class PolicyInfo { + final public String tag; + final public int label; + final public int description; + + public PolicyInfo(String tagIn, int labelIn, int descriptionIn) { + tag = tagIn; + label = labelIn; + description = descriptionIn; + } + } + + static HashMap sKnownPolicies = new HashMap(); + static SparseArray sRevKnownPolicies = new SparseArray(); + + static { + sRevKnownPolicies.put(USES_POLICY_LIMIT_PASSWORD, + new PolicyInfo("limit-password", + com.android.internal.R.string.policylab_limitPassword, + com.android.internal.R.string.policydesc_limitPassword)); + sRevKnownPolicies.put(USES_POLICY_WATCH_LOGIN, + new PolicyInfo("watch-login", + com.android.internal.R.string.policylab_watchLogin, + com.android.internal.R.string.policydesc_watchLogin)); + sRevKnownPolicies.put(USES_POLICY_RESET_PASSWORD, + new PolicyInfo("reset-password", + com.android.internal.R.string.policylab_resetPassword, + com.android.internal.R.string.policydesc_resetPassword)); + sRevKnownPolicies.put(USES_POLICY_LIMIT_UNLOCK, + new PolicyInfo("limit-unlock", + com.android.internal.R.string.policylab_limitUnlock, + com.android.internal.R.string.policydesc_limitUnlock)); + sRevKnownPolicies.put(USES_POLICY_FORCE_LOCK, + new PolicyInfo("force-lock", + com.android.internal.R.string.policylab_forceLock, + com.android.internal.R.string.policydesc_forceLock)); + sRevKnownPolicies.put(USES_POLICY_WIPE_DATA, + new PolicyInfo("wipe-data", + com.android.internal.R.string.policylab_wipeData, + com.android.internal.R.string.policydesc_wipeData)); + for (int i=0; i outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + String tagName = parser.getName(); + if (tagName.equals("uses-policies")) { + int innerDepth = parser.getDepth(); + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + String policyName = parser.getName(); + Integer val = sKnownPolicies.get(policyName); + if (val != null) { + mUsesPolicies |= 1 << val.intValue(); + } else { + Log.w(TAG, "Unknown tag under uses-policies of " + + getComponent() + ": " + policyName); + } + } + } + } } finally { if (parser != null) parser.close(); } @@ -93,6 +238,7 @@ public final class DeviceAdminInfo implements Parcelable { DeviceAdminInfo(Parcel source) { mReceiver = ResolveInfo.CREATOR.createFromParcel(source); + mUsesPolicies = source.readInt(); } /** @@ -136,6 +282,26 @@ public final class DeviceAdminInfo implements Parcelable { return mReceiver.loadLabel(pm); } + /** + * Load user-visible description associated with this device admin. + * + * @param pm Supply a PackageManager used to load the device admin's + * resources. + */ + public CharSequence loadDescription(PackageManager pm) throws NotFoundException { + if (mReceiver.activityInfo.descriptionRes != 0) { + String packageName = mReceiver.resolvePackageName; + ApplicationInfo applicationInfo = null; + if (packageName == null) { + packageName = mReceiver.activityInfo.packageName; + applicationInfo = mReceiver.activityInfo.applicationInfo; + } + return pm.getText(packageName, + mReceiver.activityInfo.descriptionRes, applicationInfo); + } + throw new NotFoundException(); + } + /** * Load the user-displayed icon for this device admin. * @@ -146,6 +312,38 @@ public final class DeviceAdminInfo implements Parcelable { return mReceiver.loadIcon(pm); } + /** + * Return true if the device admin has requested that it be able to use + * the given policy control. The possible policy identifier inputs are: + * {@link #USES_POLICY_LIMIT_PASSWORD}, {@link #USES_POLICY_WATCH_LOGIN}, + * {@link #USES_POLICY_RESET_PASSWORD}, {@link #USES_POLICY_LIMIT_UNLOCK}, + * {@link #USES_POLICY_FORCE_LOCK}, {@link #USES_POLICY_WIPE_DATA}. + */ + public boolean usesPolicy(int policyIdent) { + return (mUsesPolicies & (1< getUsedPolicies() { + ArrayList res = new ArrayList(); + for (int i=0; iThe calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call + * this method; if it has not, a security exception will be thrown. + * * @param admin Which {@link DeviceAdmin} this request is associated with. * @param mode The new desired mode. One of * {@link #PASSWORD_MODE_UNSPECIFIED}, {@link #PASSWORD_MODE_SOMETHING}, @@ -205,6 +209,10 @@ public class DevicePolicyManager { * {@link #PASSWORD_MODE_NUMERIC} or {@link #PASSWORD_MODE_ALPHANUMERIC} * with {@link #setPasswordMode}. * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call + * this method; if it has not, a security exception will be thrown. + * * @param admin Which {@link DeviceAdmin} this request is associated with. * @param length The new desired minimum password length. A value of 0 * means there is no restriction. @@ -239,6 +247,10 @@ public class DevicePolicyManager { * to meet the policy requirements (mode, minimum length) that have been * requested. * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call + * this method; if it has not, a security exception will be thrown. + * * @return Returns true if the password meets the current requirements, * else false. */ @@ -256,6 +268,10 @@ public class DevicePolicyManager { /** * Retrieve the number of times the user has failed at entering a * password since that last successful password entry. + * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call + * this method; if it has not, a security exception will be thrown. */ public int getCurrentFailedPasswordAttempts() { if (mService != null) { @@ -277,6 +293,10 @@ public class DevicePolicyManager { * if it contains only digits, that is still an acceptable alphanumeric * password.) * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call + * this method; if it has not, a security exception will be thrown. + * * @param password The new password for the user. * @return Returns true if the password was applied, or false if it is * not acceptable for the current constraints. @@ -297,6 +317,10 @@ public class DevicePolicyManager { * maximum time for user activity until the device will lock. This limits * the length that the user can set. It takes effect immediately. * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_LIMIT_UNLOCK} to be able to call + * this method; if it has not, a security exception will be thrown. + * * @param admin Which {@link DeviceAdmin} this request is associated with. * @param timeMs The new desired maximum time to lock in milliseconds. * A value of 0 means there is no restriction. @@ -329,6 +353,10 @@ public class DevicePolicyManager { /** * Make the device lock immediately, as if the lock screen timeout has * expired at the point of this call. + * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call + * this method; if it has not, a security exception will be thrown. */ public void lockNow() { if (mService != null) { @@ -345,6 +373,10 @@ public class DevicePolicyManager { * erasing all user data while next booting up. External storage such * as SD cards will not be erased. * + *

The calling device admin must have requested + * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call + * this method; if it has not, a security exception will be thrown. + * * @param flags Bit mask of additional options: currently must be 0. */ public void wipeData(int flags) { diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java index 1612ac9491798..5ca3fb54e2fc6 100644 --- a/core/java/android/app/WallpaperInfo.java +++ b/core/java/android/app/WallpaperInfo.java @@ -21,6 +21,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -204,7 +205,7 @@ public final class WallpaperInfo implements Parcelable { return pm.getDrawable(mService.serviceInfo.packageName, mThumbnailResource, - null); + mService.serviceInfo.applicationInfo); } /** @@ -212,25 +213,33 @@ public final class WallpaperInfo implements Parcelable { */ public CharSequence loadAuthor(PackageManager pm) throws NotFoundException { if (mAuthorResource <= 0) throw new NotFoundException(); - return pm.getText( - (mService.resolvePackageName != null) - ? mService.resolvePackageName - : getPackageName(), - mAuthorResource, - null); + String packageName = mService.resolvePackageName; + ApplicationInfo applicationInfo = null; + if (packageName == null) { + packageName = mService.serviceInfo.packageName; + applicationInfo = mService.serviceInfo.applicationInfo; + } + return pm.getText(packageName, mAuthorResource, applicationInfo); } /** * Return a brief summary of this wallpaper's behavior. */ public CharSequence loadDescription(PackageManager pm) throws NotFoundException { + String packageName = mService.resolvePackageName; + ApplicationInfo applicationInfo = null; + if (packageName == null) { + packageName = mService.serviceInfo.packageName; + applicationInfo = mService.serviceInfo.applicationInfo; + } + if (mService.serviceInfo.descriptionRes != 0) { + return pm.getText(packageName, mService.serviceInfo.descriptionRes, + applicationInfo); + + } if (mDescriptionResource <= 0) throw new NotFoundException(); - return pm.getText( - (mService.resolvePackageName != null) - ? mService.resolvePackageName - : getPackageName(), - mDescriptionResource, - null); + return pm.getText(packageName, mDescriptionResource, + mService.serviceInfo.applicationInfo); } /** diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java index 73c924482b0ac..338c62b6c8207 100644 --- a/core/java/android/content/pm/ComponentInfo.java +++ b/core/java/android/content/pm/ComponentInfo.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.content.pm; import android.graphics.drawable.Drawable; @@ -26,6 +42,13 @@ public class ComponentInfo extends PackageItemInfo { */ public String processName; + /** + * A string resource identifier (in the package's resources) containing + * a user-readable description of the component. From the "description" + * attribute or, if not set, 0. + */ + public int descriptionRes; + /** * Indicates whether or not this component may be instantiated. Note that this value can be * overriden by the one in its parent {@link ApplicationInfo}. @@ -47,6 +70,7 @@ public class ComponentInfo extends PackageItemInfo { super(orig); applicationInfo = orig.applicationInfo; processName = orig.processName; + descriptionRes = orig.descriptionRes; enabled = orig.enabled; exported = orig.exported; } @@ -108,6 +132,9 @@ public class ComponentInfo extends PackageItemInfo { super.dumpFront(pw, prefix); pw.println(prefix + "enabled=" + enabled + " exported=" + exported + " processName=" + processName); + if (descriptionRes != 0) { + pw.println(prefix + "description=" + descriptionRes); + } } protected void dumpBack(Printer pw, String prefix) { @@ -124,6 +151,7 @@ public class ComponentInfo extends PackageItemInfo { super.writeToParcel(dest, parcelableFlags); applicationInfo.writeToParcel(dest, parcelableFlags); dest.writeString(processName); + dest.writeInt(descriptionRes); dest.writeInt(enabled ? 1 : 0); dest.writeInt(exported ? 1 : 0); } @@ -132,6 +160,7 @@ public class ComponentInfo extends PackageItemInfo { super(source); applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source); processName = source.readString(); + descriptionRes = source.readInt(); enabled = (source.readInt() != 0); exported = (source.readInt() != 0); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 8a5df324e60de..bbde0a6035bad 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -119,15 +119,18 @@ public class PackageParser { static class ParseComponentArgs extends ParsePackageItemArgs { final String[] sepProcesses; final int processRes; + final int descriptionRes; final int enabledRes; int flags; ParseComponentArgs(Package _owner, String[] _outError, int _nameRes, int _labelRes, int _iconRes, - String[] _sepProcesses, int _processRes,int _enabledRes) { + String[] _sepProcesses, int _processRes, + int _descriptionRes, int _enabledRes) { super(_owner, _outError, _nameRes, _labelRes, _iconRes); sepProcesses = _sepProcesses; processRes = _processRes; + descriptionRes = _descriptionRes; enabledRes = _enabledRes; } } @@ -1602,6 +1605,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestActivity_icon, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestActivity_process, + com.android.internal.R.styleable.AndroidManifestActivity_description, com.android.internal.R.styleable.AndroidManifestActivity_enabled); } @@ -1803,6 +1807,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, mSeparateProcesses, 0, + com.android.internal.R.styleable.AndroidManifestActivityAlias_description, com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); mParseActivityAliasArgs.tag = ""; } @@ -1837,6 +1842,9 @@ public class PackageParser { info.nonLocalizedLabel = target.info.nonLocalizedLabel; info.launchMode = target.info.launchMode; info.processName = target.info.processName; + if (info.descriptionRes == 0) { + info.descriptionRes = target.info.descriptionRes; + } info.screenOrientation = target.info.screenOrientation; info.taskAffinity = target.info.taskAffinity; info.theme = target.info.theme; @@ -1926,6 +1934,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestProvider_icon, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestProvider_process, + com.android.internal.R.styleable.AndroidManifestProvider_description, com.android.internal.R.styleable.AndroidManifestProvider_enabled); mParseProviderArgs.tag = ""; } @@ -2188,6 +2197,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestService_icon, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestService_process, + com.android.internal.R.styleable.AndroidManifestService_description, com.android.internal.R.styleable.AndroidManifestService_enabled); mParseServiceArgs.tag = ""; } @@ -2640,6 +2650,11 @@ public class PackageParser { owner.applicationInfo.processName, args.sa.getNonResourceString(args.processRes), args.flags, args.sepProcesses, args.outError); } + + if (args.descriptionRes != 0) { + outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); + } + outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); } diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index a09f23cf9a9d7..aa14c81fb2507 100755 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -146,6 +146,19 @@ public class AppSecurityPermissions implements View.OnClickListener { } } + /** + * Utility to retrieve a view displaying a single permission. + */ + public static View getPermissionItemView(Context context, + CharSequence grpName, CharSequence description, boolean dangerous) { + LayoutInflater inflater = (LayoutInflater)context.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + Drawable icon = context.getResources().getDrawable(dangerous + ? R.drawable.ic_bullet_key_permission : R.drawable.ic_text_dot); + return getPermissionItemView(context, inflater, grpName, + description, dangerous, icon); + } + private void getAllUsedPermissions(int sharedUid, Set permSet) { String sharedPkgList[] = mPm.getPackagesForUid(sharedUid); if(sharedPkgList == null || (sharedPkgList.length == 0)) { @@ -304,15 +317,20 @@ public class AppSecurityPermissions implements View.OnClickListener { mNoPermsView.setVisibility(View.VISIBLE); } - private View getPermissionItemView(CharSequence grpName, String permList, + private View getPermissionItemView(CharSequence grpName, CharSequence permList, boolean dangerous) { - View permView = mInflater.inflate(R.layout.app_permission_item, null); - Drawable icon = dangerous ? mDangerousIcon : mNormalIcon; + return getPermissionItemView(mContext, mInflater, grpName, permList, + dangerous, dangerous ? mDangerousIcon : mNormalIcon); + } + + private static View getPermissionItemView(Context context, LayoutInflater inflater, + CharSequence grpName, CharSequence permList, boolean dangerous, Drawable icon) { + View permView = inflater.inflate(R.layout.app_permission_item, null); TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group); TextView permDescView = (TextView) permView.findViewById(R.id.permission_list); if (dangerous) { - final Resources resources = mContext.getResources(); + final Resources resources = context.getResources(); permGrpView.setTextColor(resources.getColor(R.color.perms_dangerous_grp_color)); permDescView.setTextColor(resources.getColor(R.color.perms_dangerous_perm_color)); } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index c6ef3a0c12fe8..7728c501a6a6b 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -938,6 +938,7 @@ is a period then it is appended to your package name. --> + @@ -1016,6 +1017,7 @@ is a period then it is appended to your package name. --> + @@ -1047,6 +1049,7 @@ is a period then it is appended to your package name. --> + @@ -1078,6 +1081,7 @@ + @@ -1130,6 +1134,7 @@ "com.mycompany.MyName". --> + Allows an application to read and write the cache filesystem. + + + + Limit password + + Restrict the types of passwords you + are allowed to use. + + Watch login attempts + + Monitor attempts to login to + the device, in particular to respond to failed login attempts. + + Reset your password + + Force your password + to a new value, requiring the administrator give it to you + before you can log in. + + Limit lock timeout + + Restrict the unlock timeout + durations you can select. + + Force lock + + Force the device to immediately lock, + requiring that its password is re-entered. + + Erase all data + + Perform a factory reset, deleting + all of your data without any confirmation from you. + diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 36da4eb3d65c4..fbd53173fd0be 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -91,7 +91,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return mIPowerManager; } - ActiveAdmin getActiveAdminForCallerLocked(ComponentName who) throws SecurityException { + ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) + throws SecurityException { if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingUid()) { if (who != null) { if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName) @@ -99,20 +100,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new SecurityException("Current admin is not " + who); } } + if (!mActiveAdmin.info.usesPolicy(reqPolicy)) { + throw new SecurityException("Admin " + mActiveAdmin.info.getComponent() + + " did not specify uses-policy for: " + + mActiveAdmin.info.getTagForPolicy(reqPolicy)); + } return mActiveAdmin; } throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid()); } - - void sendAdminCommandLocked(ActiveAdmin policy, String action) { + void sendAdminCommandLocked(ActiveAdmin admin, String action) { Intent intent = new Intent(action); - intent.setComponent(policy.info.getComponent()); + intent.setComponent(admin.info.getComponent()); mContext.sendBroadcast(intent); } - void sendAdminCommandLocked(String action) { + void sendAdminCommandLocked(String action, int reqPolicy) { if (mActiveAdmin != null) { + if (mActiveAdmin.info.usesPolicy(reqPolicy)) { + return; + } sendAdminCommandLocked(mActiveAdmin, action); } } @@ -353,7 +361,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (who == null) { throw new NullPointerException("ComponentName is null"); } - ActiveAdmin ap = getActiveAdminForCallerLocked(who); + ActiveAdmin ap = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.passwordMode != mode) { ap.passwordMode = mode; saveSettingsLocked(); @@ -373,7 +382,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (who == null) { throw new NullPointerException("ComponentName is null"); } - ActiveAdmin ap = getActiveAdminForCallerLocked(who); + ActiveAdmin ap = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordLength != length) { ap.minimumPasswordLength = length; saveSettingsLocked(); @@ -391,7 +401,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null); + getActiveAdminForCallerLocked(null, + DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); return mActivePasswordMode >= getPasswordMode() && mActivePasswordLength >= getMinimumPasswordLength(); } @@ -401,7 +412,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null); + getActiveAdminForCallerLocked(null, + DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); return mFailedPasswordAttempts; } } @@ -411,7 +423,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null); + getActiveAdminForCallerLocked(null, + DeviceAdminInfo.USES_POLICY_RESET_PASSWORD); mode = getPasswordMode(); if (password.length() < getMinimumPasswordLength()) { return false; @@ -436,7 +449,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (who == null) { throw new NullPointerException("ComponentName is null"); } - ActiveAdmin ap = getActiveAdminForCallerLocked(who); + ActiveAdmin ap = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_LIMIT_UNLOCK); if (ap.maximumTimeToUnlock != timeMs) { ap.maximumTimeToUnlock = timeMs; @@ -468,7 +482,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null); + getActiveAdminForCallerLocked(null, + DeviceAdminInfo.USES_POLICY_FORCE_LOCK); // STOPSHIP need to implement. } } @@ -477,7 +492,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null); + getActiveAdminForCallerLocked(null, + DeviceAdminInfo.USES_POLICY_WIPE_DATA); } long ident = Binder.clearCallingIdentity(); try { @@ -501,7 +517,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mActivePasswordMode = mode; mActivePasswordLength = length; mFailedPasswordAttempts = 0; - sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_CHANGED); + sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_CHANGED, + DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); } finally { Binder.restoreCallingIdentity(ident); } @@ -517,7 +534,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long ident = Binder.clearCallingIdentity(); try { mFailedPasswordAttempts++; - sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_FAILED); + sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_FAILED, + DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); } finally { Binder.restoreCallingIdentity(ident); } @@ -533,7 +551,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long ident = Binder.clearCallingIdentity(); try { mFailedPasswordAttempts = 0; - sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_SUCCEEDED); + sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_SUCCEEDED, + DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); } finally { Binder.restoreCallingIdentity(ident); }