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:
@@ -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 \
|
||||
|
||||
1623
api/current.xml
1623
api/current.xml
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user