Move DeviceAdmin APIs to android.app.admin.

Also add ability for admins to hide themselves when not in use,
a facility for admins to not allow other admins to reset
their password, and debug dumping.
This commit is contained in:
Dianne Hackborn
2010-02-26 17:25:54 -08:00
parent 8c49df4f36
commit 87bba1ee14
13 changed files with 997 additions and 819 deletions

View File

@@ -81,7 +81,6 @@ LOCAL_SRC_FILES += \
core/java/android/app/IActivityWatcher.aidl \
core/java/android/app/IAlarmManager.aidl \
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IDevicePolicyManager.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
core/java/android/app/INotificationManager.aidl \
core/java/android/app/ISearchManager.aidl \
@@ -93,6 +92,7 @@ LOCAL_SRC_FILES += \
core/java/android/app/IUiModeManager.aidl \
core/java/android/app/IWallpaperManager.aidl \
core/java/android/app/IWallpaperManagerCallback.aidl \
core/java/android/app/admin/IDevicePolicyManager.aidl \
core/java/android/backup/IBackupManager.aidl \
core/java/android/backup/IRestoreObserver.aidl \
core/java/android/backup/IRestoreSession.aidl \

File diff suppressed because it is too large Load Diff

View File

@@ -99,6 +99,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.InputMethodManager;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.app.admin.DevicePolicyManager;
import com.android.internal.os.IDropBoxManagerService;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package android.app;
package android.app.admin;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -149,6 +149,11 @@ public final class DeviceAdminInfo implements Parcelable {
*/
final ResolveInfo mReceiver;
/**
* Whether this should be visible to the user.
*/
boolean mVisible;
/**
* The policies this administrator needs access to.
*/
@@ -190,8 +195,11 @@ public final class DeviceAdminInfo implements Parcelable {
}
TypedArray sa = context.getResources().obtainAttributes(attrs,
com.android.internal.R.styleable.Wallpaper);
com.android.internal.R.styleable.DeviceAdmin);
mVisible = sa.getBoolean(
com.android.internal.R.styleable.DeviceAdmin_visible, true);
sa.recycle();
int outerDepth = parser.getDepth();
@@ -300,6 +308,14 @@ public final class DeviceAdminInfo implements Parcelable {
return mReceiver.loadIcon(pm);
}
/**
* Returns whether this device admin would like to be visible to the
* user, even when it is not enabled.
*/
public boolean isVisible() {
return mVisible;
}
/**
* Return true if the device admin has requested that it be able to use
* the given policy control. The possible policy identifier inputs are:

View File

@@ -14,10 +14,11 @@
* limitations under the License.
*/
package android.app;
package android.app.admin;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;

View File

@@ -14,12 +14,13 @@
* limitations under the License.
*/
package android.app;
package android.app.admin;
import org.xmlpull.v1.XmlPullParserException;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.admin.IDevicePolicyManager.Stub;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -56,7 +57,8 @@ public class DevicePolicyManager {
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
}
/*package*/ static DevicePolicyManager create(Context context, Handler handler) {
/** @hide */
public static DevicePolicyManager create(Context context, Handler handler) {
DevicePolicyManager me = new DevicePolicyManager(context, handler);
return me.mService != null ? me : null;
}
@@ -393,6 +395,12 @@ public class DevicePolicyManager {
return 0;
}
/**
* Flag for {@link #resetPassword}: don't allow other admins to change
* the password again until the user has entered it.
*/
public static final int RESET_PASSWORD_REQUIRE_ENTRY = 0x0001;
/**
* Force a new device unlock password (the password needed to access the
* entire device, not for individual accounts) on the user. This takes
@@ -411,13 +419,14 @@ public class DevicePolicyManager {
* this method; if it has not, a security exception will be thrown.
*
* @param password The new password for the user.
* @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}.
* @return Returns true if the password was applied, or false if it is
* not acceptable for the current constraints.
*/
public boolean resetPassword(String password) {
public boolean resetPassword(String password, int flags) {
if (mService != null) {
try {
return mService.resetPassword(password);
return mService.resetPassword(password, flags);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}

View File

@@ -15,7 +15,7 @@
** limitations under the License.
*/
package android.app;
package android.app.admin;
import android.content.ComponentName;
import android.os.RemoteCallback;
@@ -37,7 +37,7 @@ interface IDevicePolicyManager {
void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
int getMaximumFailedPasswordsForWipe(in ComponentName admin);
boolean resetPassword(String password);
boolean resetPassword(String password, int flags);
void setMaximumTimeToLock(in ComponentName who, long timeMs);
long getMaximumTimeToLock(in ComponentName who);

View File

@@ -1507,7 +1507,7 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.app.DevicePolicyManager} for working with global
* {@link android.app.admin.DevicePolicyManager} for working with global
* device policy management.
*
* @see #getSystemService

View File

@@ -16,7 +16,7 @@
package com.android.internal.widget;
import android.app.DevicePolicyManager;
import android.app.admin.DevicePolicyManager;
import android.content.ContentResolver;
import android.content.Context;
import android.os.RemoteException;

View File

@@ -3501,6 +3501,21 @@
<!-- =============================== -->
<eat-comment />
<!-- Use <code>device-admin</code> as the root tag of the XML resource that
describes a
{@link android.app.admin.DeviceAdminReceiver}, which is
referenced from its
{@link android.app.admin.DeviceAdminReceiver#DEVICE_ADMIN_META_DATA}
meta-data entry. Described here are the attributes that can be
included in that tag. -->
<declare-styleable name="DeviceAdmin">
<!-- Control whether the admin is visible to the user, even when it
is not enabled. This is true by default. You may want to make
it false if your admin does not make sense to be turned on
unless some explicit action happens in your app. -->
<attr name="visible" />
</declare-styleable>
<!-- Use <code>wallpaper</code> as the root tag of the XML resource that
describes an
{@link android.service.wallpaper.WallpaperService}, which is

View File

@@ -31,7 +31,6 @@ android.app.ExpandableListActivity
android.app.IActivityManager
android.app.IActivityManager$ContentProviderHolder
android.app.IAlarmManager$Stub
android.app.IDevicePolicyManager$Stub
android.app.IStatusBar$Stub
android.app.ITransientNotification$Stub
android.app.Instrumentation
@@ -51,6 +50,7 @@ android.app.SuggestionsAdapter
android.app.SuperNotCalledException
android.app.TabActivity
android.app.TimePickerDialog
android.app.admin.IDevicePolicyManager$Stub
android.appwidget.AppWidgetHost
android.appwidget.AppWidgetHostView
android.appwidget.AppWidgetHostView$ParcelableSparseArray

View File

@@ -26,10 +26,10 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.app.Activity;
import android.app.DeviceAdminReceiver;
import android.app.DeviceAdminInfo;
import android.app.DevicePolicyManager;
import android.app.IDevicePolicyManager;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -46,13 +46,17 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Xml;
import android.view.WindowManagerPolicy;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -72,6 +76,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
int mActivePasswordLength = 0;
int mFailedPasswordAttempts = 0;
int mPasswordOwner = -1;
final HashMap<ComponentName, ActiveAdmin> mAdminMap
= new HashMap<ComponentName, ActiveAdmin>();
final ArrayList<ActiveAdmin> mAdminList
@@ -148,11 +154,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
XmlUtils.skipCurrentTag(parser);
}
}
void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("uid="); pw.println(getUid());
pw.print(prefix); pw.println("policies:");
ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
if (pols != null) {
for (int i=0; i<pols.size(); i++) {
pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
}
}
pw.print(prefix); pw.print("passwordQuality=");
pw.print(passwordQuality);
pw.print(" minimumPasswordLength=");
pw.println(minimumPasswordLength);
pw.print(prefix); pw.print("maximumTimeToUnlock=");
pw.println(maximumTimeToUnlock);
pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
pw.println(maximumFailedPasswordsForWipe);
}
}
class MyPackageMonitor extends PackageMonitor {
public void onSomePackagesChanged() {
synchronized (DevicePolicyManagerService.this) {
boolean removed = false;
for (int i=mAdminList.size()-1; i>=0; i--) {
ActiveAdmin aa = mAdminList.get(i);
int change = isPackageDisappearing(aa.info.getPackageName());
@@ -160,6 +186,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|| change == PACKAGE_TEMPORARY_CHANGE) {
Log.w(TAG, "Admin unexpectedly uninstalled: "
+ aa.info.getComponent());
removed = true;
mAdminList.remove(i);
} else if (isPackageModified(aa.info.getPackageName())) {
try {
@@ -168,10 +195,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} catch (NameNotFoundException e) {
Log.w(TAG, "Admin package change removed component: "
+ aa.info.getComponent());
removed = true;
mAdminList.remove(i);
}
}
}
if (removed) {
validatePasswordOwnerLocked();
}
}
}
}
@@ -260,6 +291,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// XXX need to wait for it to complete.
mAdminList.remove(admin);
mAdminMap.remove(adminReceiver);
validatePasswordOwnerLocked();
}
}
@@ -312,6 +344,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
out.endTag(null, "policies");
if (mPasswordOwner >= 0) {
out.startTag(null, "password-owner");
out.attribute(null, "value", Integer.toString(mPasswordOwner));
out.endTag(null, "password-owner");
}
if (mFailedPasswordAttempts != 0) {
out.startTag(null, "failed-password-attempts");
out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
@@ -377,6 +415,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mFailedPasswordAttempts = Integer.parseInt(
parser.getAttributeValue(null, "value"));
XmlUtils.skipCurrentTag(parser);
} else if ("password-owner".equals(tag)) {
mPasswordOwner = Integer.parseInt(
parser.getAttributeValue(null, "value"));
XmlUtils.skipCurrentTag(parser);
} else {
Log.w(TAG, "Unknown tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -401,6 +443,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Ignore
}
validatePasswordOwnerLocked();
long timeMs = getMaximumTimeToLock(null);
if (timeMs <= 0) {
timeMs = Integer.MAX_VALUE;
@@ -412,6 +456,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
void validatePasswordOwnerLocked() {
if (mPasswordOwner >= 0) {
boolean haveOwner = false;
for (int i=mAdminList.size()-1; i>=0; i--) {
if (mAdminList.get(i).getUid() == mPasswordOwner) {
haveOwner = true;
break;
}
}
if (!haveOwner) {
Log.w(TAG, "Previous password owner " + mPasswordOwner
+ " no longer active; disabling");
mPasswordOwner = -1;
}
}
}
public void systemReady() {
synchronized (this) {
loadSettingsLocked();
@@ -622,7 +683,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
public boolean resetPassword(String password) {
public boolean resetPassword(String password, int flags) {
int quality;
synchronized (this) {
// This API can only be called by an active device admin,
@@ -645,12 +706,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
int callingUid = Binder.getCallingUid();
if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
Log.w(TAG, "resetPassword: already set by another uid and not entered by user");
return false;
}
// Don't do this with the lock held, because it is going to call
// back in to the service.
long ident = Binder.clearCallingIdentity();
try {
LockPatternUtils utils = new LockPatternUtils(mContext);
utils.saveLockPassword(password, quality);
int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
!= 0 ? callingUid : -1;
if (mPasswordOwner != newOwner) {
mPasswordOwner = newOwner;
saveSettingsLocked();
}
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -829,10 +902,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
synchronized (this) {
if (mFailedPasswordAttempts != 0) {
if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
long ident = Binder.clearCallingIdentity();
try {
mFailedPasswordAttempts = 0;
mPasswordOwner = -1;
saveSettingsLocked();
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
@@ -842,4 +916,39 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
}
final Printer p = new PrintWriterPrinter(pw);
synchronized (this) {
p.println("Current Device Policy Manager state:");
p.println(" Enabled Device Admins:");
final int N = mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin ap = mAdminList.get(i);
if (ap != null) {
pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
pw.println(":");
ap.dump(" ", pw);
}
}
pw.println(" ");
pw.print(" mActivePasswordQuality="); pw.println(mActivePasswordQuality);
pw.print(" mActivePasswordLength="); pw.println(mActivePasswordLength);
pw.print(" mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
pw.print(" mPasswordOwner="); pw.println(mPasswordOwner);
}
}
}

View File

@@ -28,9 +28,9 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManagerNative;
import android.app.DevicePolicyManager;
import android.app.IActivityManager;
import android.app.IDevicePolicyManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.backup.IBackupManager;
import android.content.ComponentName;
import android.content.Context;