summaryrefslogtreecommitdiffstats
path: root/services/devicepolicy
diff options
context:
space:
mode:
authorJulia Reynolds <juliacr@google.com>2015-02-11 12:34:08 -0500
committerJulia Reynolds <juliacr@google.com>2015-03-04 10:25:43 -0500
commit20118f18c11c01c7743b5646cc1a0039c2e90037 (patch)
tree85e6b2a6d9e82b3266965a69d2e315c36c4338eb /services/devicepolicy
parentd5fe9f60b3af05f91ca0548c4fb91745dd2a85b1 (diff)
downloadframeworks_base-20118f18c11c01c7743b5646cc1a0039c2e90037.zip
frameworks_base-20118f18c11c01c7743b5646cc1a0039c2e90037.tar.gz
frameworks_base-20118f18c11c01c7743b5646cc1a0039c2e90037.tar.bz2
Allow the device initializer to perform user setup tasks.
A device initializer is an application that is allowed to run during user provisioning on device owner devices. During device provisioning (or, user provisioning of the first user of the device), a device initializer is granted device owner permissions. During secondary user provisioning, a device initializer is granted profile owner permissions. Once provisioning is complete for a user, all elevated permissions are removed from the device initializer and the device admin component of the app is disabled. Bug: 19230954 Change-Id: Ib6725fb3b09bb21e4198a5dc0b445ccebb40b27e
Diffstat (limited to 'services/devicepolicy')
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java47
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java159
2 files changed, 203 insertions, 3 deletions
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 57ed876..ea59d4b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -53,6 +53,7 @@ class DeviceOwner {
private static final String DEVICE_OWNER_XML = "device_owner.xml";
private static final String TAG_DEVICE_OWNER = "device-owner";
+ private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
private static final String TAG_PROFILE_OWNER = "profile-owner";
private static final String ATTR_NAME = "name";
private static final String ATTR_PACKAGE = "package";
@@ -68,6 +69,9 @@ class DeviceOwner {
// Internal state for the device owner package.
private OwnerInfo mDeviceOwner;
+ // Internal state for the device initializer package.
+ private OwnerInfo mDeviceInitializer;
+
// Internal state for the profile owner packages.
private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
@@ -104,6 +108,15 @@ class DeviceOwner {
}
/**
+ * Creates an instance of the device owner object with the device initializer set.
+ */
+ static DeviceOwner createWithDeviceInitializer(String packageName, String ownerName) {
+ DeviceOwner owner = new DeviceOwner();
+ owner.mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+ return owner;
+ }
+
+ /**
* Creates an instance of the device owner object with the profile owner set.
*/
static DeviceOwner createWithProfileOwner(ComponentName admin, String ownerName, int userId) {
@@ -128,6 +141,26 @@ class DeviceOwner {
mDeviceOwner = null;
}
+ String getDeviceInitializerPackageName() {
+ return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
+ }
+
+ String getDeviceInitializerName() {
+ return mDeviceInitializer != null ? mDeviceInitializer.name : null;
+ }
+
+ void setDeviceInitializer(String packageName, String ownerName) {
+ mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+ }
+
+ void clearDeviceInitializer() {
+ mDeviceInitializer = null;
+ }
+
+ boolean hasDeviceInitializer() {
+ return mDeviceInitializer != null;
+ }
+
void setProfileOwner(ComponentName admin, String ownerName, int userId) {
mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
}
@@ -199,6 +232,10 @@ class DeviceOwner {
String name = parser.getAttributeValue(null, ATTR_NAME);
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
mDeviceOwner = new OwnerInfo(name, packageName);
+ } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+ mDeviceInitializer = new OwnerInfo(name, packageName);
} else if (tag.equals(TAG_PROFILE_OWNER)) {
String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -259,6 +296,16 @@ class DeviceOwner {
out.endTag(null, TAG_DEVICE_OWNER);
}
+ // Write device initializer tag
+ if (mDeviceInitializer != null) {
+ out.startTag(null, TAG_DEVICE_INITIALIZER);
+ out.attribute(null, ATTR_PACKAGE, mDeviceInitializer.packageName);
+ if (mDeviceInitializer.name != null) {
+ out.attribute(null, ATTR_NAME, mDeviceInitializer.name);
+ }
+ out.endTag(null, TAG_DEVICE_INITIALIZER);
+ }
+
// Write profile owner tags
if (mProfileOwners.size() > 0) {
for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a19cd9f..6270212 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1139,13 +1139,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean ownsProfile = (getProfileOwner(userHandle) != null
&& getProfileOwner(userHandle).getPackageName()
.equals(admin.info.getPackageName()));
+ boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
+ && !hasUserSetupCompleted(userHandle);
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
- if (ownsDevice) {
+ if (ownsDevice || (userHandle == UserHandle.USER_OWNER && ownsInitialization)) {
return admin;
}
} else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
- if (ownsDevice || ownsProfile) {
+ if (ownsDevice || ownsProfile || ownsInitialization) {
return admin;
}
} else {
@@ -1899,7 +1901,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
if (admin.getUid() != Binder.getCallingUid()) {
- // If trying to remove device owner, refuse when the caller is not the owner.
+ // Active device owners must remain active admins.
if (isDeviceOwner(adminReceiver.getPackageName())) {
return;
}
@@ -3866,6 +3868,112 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
+ public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
+ String ownerName) {
+ if (!mHasFeature) {
+ return false;
+ }
+ if (initializer == null || !DeviceOwner.isInstalled(
+ initializer.getPackageName(), mContext.getPackageManager())) {
+ throw new IllegalArgumentException("Invalid component name " + initializer
+ + " for device initializer");
+ }
+ synchronized (this) {
+ enforceCanSetDeviceInitializer(who);
+
+ if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+ throw new IllegalStateException(
+ "Trying to set device initializer but device initializer is already set.");
+ }
+
+ if (mDeviceOwner == null) {
+ // Device owner state does not exist, create it.
+ mDeviceOwner = DeviceOwner.createWithDeviceInitializer(
+ initializer.getPackageName(), ownerName);
+ mDeviceOwner.writeOwnerFile();
+ return true;
+ } else {
+ // Device owner already exists, update it.
+ mDeviceOwner.setDeviceInitializer(initializer.getPackageName(), ownerName);
+ mDeviceOwner.writeOwnerFile();
+ return true;
+ }
+ }
+ }
+
+ private void enforceCanSetDeviceInitializer(ComponentName who) {
+ if (who == null) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
+ if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+ throw new IllegalStateException(
+ "Trying to set device initializer but device is already provisioned.");
+ }
+ } else {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+ }
+
+ @Override
+ public boolean isDeviceInitializer(String packageName) {
+ if (!mHasFeature) {
+ return false;
+ }
+ synchronized (this) {
+ return mDeviceOwner != null
+ && mDeviceOwner.hasDeviceInitializer()
+ && mDeviceOwner.getDeviceInitializerPackageName().equals(packageName);
+ }
+ }
+
+ @Override
+ public String getDeviceInitializer() {
+ if (!mHasFeature) {
+ return null;
+ }
+ synchronized (this) {
+ if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+ return mDeviceOwner.getDeviceInitializerPackageName();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void clearDeviceInitializer(String packageName) {
+ if (!mHasFeature) {
+ return;
+ }
+ if (packageName == null) {
+ throw new NullPointerException("packageName is null");
+ }
+ try {
+ int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
+ if (uid != Binder.getCallingUid()) {
+ throw new SecurityException(
+ "clearDeviceInitializer can only be called by the device initializer");
+ }
+ } catch (NameNotFoundException e) {
+ throw new SecurityException(e);
+ }
+ if (!isDeviceInitializer(packageName)) {
+ throw new SecurityException(
+ "clearDeviceInitializer can only be called by the device initializer");
+ }
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (mDeviceOwner != null) {
+ mDeviceOwner.clearDeviceInitializer();
+ mDeviceOwner.writeOwnerFile();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3960,6 +4068,51 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
+ public boolean setUserEnabled(ComponentName who) {
+ if (!mHasFeature) {
+ return false;
+ }
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ int userId = UserHandle.getCallingUserId();
+
+ ActiveAdmin activeAdmin =
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!isDeviceInitializer(activeAdmin.info.getPackageName())) {
+ throw new SecurityException(
+ "This method can only be called by device initializers");
+ }
+
+ long id = Binder.clearCallingIdentity();
+ try {
+ if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ ipm.setComponentEnabledSetting(who,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP, userId);
+
+ removeActiveAdmin(who, userId);
+ }
+
+ if (userId == UserHandle.USER_OWNER) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+ }
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 1, userId);
+ } catch (RemoteException e) {
+ Log.i(LOG_TAG, "Can't talk to package manager", e);
+ return false;
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ return true;
+ }
+ }
+
+ @Override
public void setProfileEnabled(ComponentName who) {
if (!mHasFeature) {
return;