diff options
| author | 2017-02-13 18:12:15 +0000 | |
|---|---|---|
| committer | 2017-04-03 19:10:59 +0100 | |
| commit | 3b8b46f3a46ccf35a6bb6a828af0f2d011cc9abe (patch) | |
| tree | 7b30ae20e755619f16d0d54f1aae4bd0cd9cf2c6 | |
| parent | ef3a28cb92039c198ed8e78a69d00bd9c8322dab (diff) | |
Service for OEM lock management.
The new service separates OEM lock management from the implementation.
Currently, a user restriction (DISALLOW_OEM_UNLOCK) and the persistent
data block have been used to implement OEM lock management. In future,
other implemention will be used e.g. a secure element.
The new API also allows for a signature to be passed when changing
whether the device is allowed to be OEM unlocked by the carrier which
can be used for cryptographic protection of the flag.
Bug: 34766843
Test: gts-tradefed run gts -m GtsOemLockServiceTestCases -t com.google.android.oemlock.gts.OemLockServiceTest
Test: cts-tradefed run cts -m CtsPermission2TestCases -t android.permission2.cts.PrivappPermissionsTest
Change-Id: I01660d7605d297f273d43436ca03d64ff611b6cf
| -rw-r--r-- | Android.mk | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 20 | ||||
| -rw-r--r-- | core/java/android/app/SystemServiceRegistry.java | 16 | ||||
| -rw-r--r-- | core/java/android/content/Context.java | 12 | ||||
| -rw-r--r-- | core/java/android/os/UserManager.java | 2 | ||||
| -rw-r--r-- | core/java/android/service/oemlock/IOemLockService.aidl | 30 | ||||
| -rw-r--r-- | core/java/android/service/oemlock/OemLockManager.java | 110 | ||||
| -rw-r--r-- | core/java/android/service/persistentdata/PersistentDataBlockManager.java | 4 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 10 | ||||
| -rw-r--r-- | services/core/java/com/android/server/OemLockService.java | 147 | ||||
| -rw-r--r-- | services/java/com/android/server/SystemServer.java | 5 |
11 files changed, 354 insertions, 3 deletions
diff --git a/Android.mk b/Android.mk index eb649c9152c3..57235b03ad62 100644 --- a/Android.mk +++ b/Android.mk @@ -308,6 +308,7 @@ LOCAL_SRC_FILES += \ core/java/android/companion/IFindDeviceCallback.aidl \ core/java/android/service/dreams/IDreamManager.aidl \ core/java/android/service/dreams/IDreamService.aidl \ + core/java/android/service/oemlock/IOemLockService.aidl \ core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \ core/java/android/service/trust/ITrustAgentService.aidl \ core/java/android/service/trust/ITrustAgentServiceCallback.aidl \ diff --git a/api/system-current.txt b/api/system-current.txt index ac1597f0162a..b388bf985221 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -141,12 +141,14 @@ package android { field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS"; field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS"; field public static final java.lang.String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL"; + field public static final java.lang.String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE"; field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES"; field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS"; field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS"; field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB"; field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS"; + field public static final java.lang.String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE"; field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR"; field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL"; field public static final java.lang.String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"; @@ -9401,6 +9403,7 @@ package android.content { field public static final java.lang.String NFC_SERVICE = "nfc"; field public static final java.lang.String NOTIFICATION_SERVICE = "notification"; field public static final java.lang.String NSD_SERVICE = "servicediscovery"; + field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock"; field public static final java.lang.String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block"; field public static final java.lang.String POWER_SERVICE = "power"; field public static final java.lang.String PRINT_SERVICE = "print"; @@ -34483,7 +34486,7 @@ package android.os { field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"; field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media"; field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset"; - field public static final java.lang.String DISALLOW_OEM_UNLOCK = "no_oem_unlock"; + field public static final deprecated java.lang.String DISALLOW_OEM_UNLOCK = "no_oem_unlock"; field public static final java.lang.String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam"; field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls"; field public static final java.lang.String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile"; @@ -40376,15 +40379,26 @@ package android.service.notification { } +package android.service.oemlock { + + public class OemLockManager { + method public boolean isOemUnlockAllowedByCarrier(); + method public boolean isOemUnlockAllowedByUser(); + method public void setOemUnlockAllowedByCarrier(boolean, byte[]); + method public void setOemUnlockAllowedByUser(boolean); + } + +} + package android.service.persistentdata { public class PersistentDataBlockManager { method public int getDataBlockSize(); method public int getFlashLockState(); method public long getMaximumDataBlockSize(); - method public boolean getOemUnlockEnabled(); + method public deprecated boolean getOemUnlockEnabled(); method public byte[] read(); - method public void setOemUnlockEnabled(boolean); + method public deprecated void setOemUnlockEnabled(boolean); method public void wipe(); method public int write(byte[]); field public static final int FLASH_LOCK_LOCKED = 1; // 0x1 diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index f719749cc9f9..81829c81a68e 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -118,6 +118,8 @@ import android.print.IPrintManager; import android.print.PrintManager; import android.view.autofill.AutofillManager; import android.view.autofill.IAutoFillManager; +import android.service.oemlock.IOemLockService; +import android.service.oemlock.OemLockManager; import android.service.persistentdata.IPersistentDataBlockService; import android.service.persistentdata.PersistentDataBlockManager; import android.service.vr.IVrManager; @@ -741,6 +743,20 @@ final class SystemServiceRegistry { } }}); + registerService(Context.OEM_LOCK_SERVICE, OemLockManager.class, + new StaticServiceFetcher<OemLockManager>() { + @Override + public OemLockManager createService() throws ServiceNotFoundException { + IBinder b = ServiceManager.getServiceOrThrow(Context.OEM_LOCK_SERVICE); + IOemLockService oemLockService = IOemLockService.Stub.asInterface(b); + if (oemLockService != null) { + return new OemLockManager(oemLockService); + } else { + // not supported + return null; + } + }}); + registerService(Context.MEDIA_PROJECTION_SERVICE, MediaProjectionManager.class, new CachedServiceFetcher<MediaProjectionManager>() { @Override diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index dbbfe308868c..72e88f017e79 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2872,6 +2872,7 @@ public abstract class Context { BATTERY_SERVICE, JOB_SCHEDULER_SERVICE, //@hide: PERSISTENT_DATA_BLOCK_SERVICE, + //@hide: OEM_LOCK_SERVICE, MEDIA_PROJECTION_SERVICE, MIDI_SERVICE, RADIO_SERVICE, @@ -3794,6 +3795,17 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a {@link + * android.service.oemlock.OemLockManager} instance for managing the OEM lock. + * + * @see #getSystemService + * @see android.service.oemlock.OemLockManager + * @hide + */ + @SystemApi + public static final String OEM_LOCK_SERVICE = "oem_lock"; + + /** + * Use with {@link #getSystemService} to retrieve a {@link * android.media.projection.MediaProjectionManager} instance for managing * media projection sessions. * @see #getSystemService diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index a6bf2d26abb3..6f4c9cf7d7ff 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -682,8 +682,10 @@ public class UserManager { * @see DevicePolicyManager#addUserRestriction(ComponentName, String) * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() + * @deprecated use {@link OemLockManager#setOemUnlockAllowedByCarrier(boolean, byte[])} instead. * @hide */ + @Deprecated @SystemApi public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock"; diff --git a/core/java/android/service/oemlock/IOemLockService.aidl b/core/java/android/service/oemlock/IOemLockService.aidl new file mode 100644 index 000000000000..2c606f97ab9f --- /dev/null +++ b/core/java/android/service/oemlock/IOemLockService.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2017 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.service.oemlock; + +/** + * Interface for communication with the OemLockService. + * + * @hide + */ +interface IOemLockService { + void setOemUnlockAllowedByCarrier(boolean allowed, in byte[] signature); + boolean isOemUnlockAllowedByCarrier(); + + void setOemUnlockAllowedByUser(boolean allowed); + boolean isOemUnlockAllowedByUser(); +} diff --git a/core/java/android/service/oemlock/OemLockManager.java b/core/java/android/service/oemlock/OemLockManager.java new file mode 100644 index 000000000000..c4fbe5ec7e1a --- /dev/null +++ b/core/java/android/service/oemlock/OemLockManager.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2017 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.service.oemlock; + +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.RemoteException; + +/** + * Interface for managing the OEM lock on the device. + * + * This will only be available if the device implements OEM lock protection. + * + * Multiple actors have an opinion on whether the device can be OEM unlocked and they must all be in + * agreement for unlock to be possible. + * + * @hide + */ +@SystemApi +public class OemLockManager { + private IOemLockService mService; + + /** @hide */ + public OemLockManager(IOemLockService service) { + mService = service; + } + + /** + * Sets whether the carrier has allowed this device to be OEM unlocked. + * + * Depending on the implementation, the validity of the request might need to be proved. This + * can be acheived by passing a signature that the system will use to verify the request is + * legitimate. + * + * All actors involved must agree for OEM unlock to be possible. + * + * @param allowed Whether the device should be allowed to be unlocked. + * @param signature Optional proof of request validity, {@code null} for none. + * @throws IllegalArgumentException if a signature is required but was not provided. + * @throws SecurityException if the wrong signature was provided. + * + * @see #isOemUnlockAllowedByCarrier() + */ + public void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) { + try { + mService.setOemUnlockAllowedByCarrier(allowed, signature); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns whether the carrier has allowed this device to be OEM unlocked. + * @return Whether OEM unlock is allowed by the carrier, or true if no OEM lock is present. + * + * @see #setOemUnlockAllowedByCarrier(boolean, byte[]) + */ + public boolean isOemUnlockAllowedByCarrier() { + try { + return mService.isOemUnlockAllowedByCarrier(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets whether the user has allowed this device to be unlocked. + * + * All actors involved must agree for OEM unlock to be possible. + * + * @param unlocked Whether the device should be made OEM unlocked. + * + * @see #isOemUnlockAllowedByUser() + */ + public void setOemUnlockAllowedByUser(boolean allowed) { + try { + mService.setOemUnlockAllowedByUser(allowed); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns whether, or not, the user has allowed this device to be OEM unlocked. + * @return Whether OEM unlock is allowed by the user, or true if no OEM lock is present. + * + * @see #setOemUnlockAllowedByUser(boolean) + */ + public boolean isOemUnlockAllowedByUser() { + try { + return mService.isOemUnlockAllowedByUser(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java index cb021bc03087..326796afb3ad 100644 --- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java +++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java @@ -146,6 +146,8 @@ public class PersistentDataBlockManager { /** * Writes a byte enabling or disabling the ability to "OEM unlock" the device. + * + * @deprecated use {@link OemLockManager#setOemUnlockAllowedByUser(boolean)} instead. */ public void setOemUnlockEnabled(boolean enabled) { try { @@ -157,6 +159,8 @@ public class PersistentDataBlockManager { /** * Returns whether or not "OEM unlock" is enabled or disabled on this device. + * + * @deprecated use {@link OemLockManager#isOemUnlockAllowedByUser()} instead. */ public boolean getOemUnlockEnabled() { try { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 362794e81c55..126a08b8de71 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1511,6 +1511,16 @@ <permission android:name="android.permission.DVB_DEVICE" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows reading and enabling/disabling the OEM unlock allowed by carrier state + @hide <p>Not for use by third-party applications. --> + <permission android:name="android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE" + android:protectionLevel="signature|privileged" /> + + <!-- @SystemApi Allows reading and enabling/disabling the OEM unlock allowed by user state + @hide <p>Not for use by third-party applications. --> + <permission android:name="android.permission.MANAGE_USER_OEM_UNLOCK_STATE" + android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows reading the OEM unlock state @hide <p>Not for use by third-party applications. --> <permission android:name="android.permission.READ_OEM_UNLOCK_STATE" diff --git a/services/core/java/com/android/server/OemLockService.java b/services/core/java/com/android/server/OemLockService.java new file mode 100644 index 000000000000..03f82a8e5d8e --- /dev/null +++ b/services/core/java/com/android/server/OemLockService.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2017 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 com.android.server; + +import android.Manifest; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.content.Context; +import android.os.Binder; +import android.os.IBinder; +import android.os.UserHandle; +import android.os.UserManager; +import android.service.oemlock.IOemLockService; +import android.service.persistentdata.PersistentDataBlockManager; + +/** + * Service for managing the OEM lock state of the device. + * + * The current implementation is a wrapper around the previous implementation of OEM lock. + * - the DISALLOW_OEM_UNLOCK user restriction was set if the carrier disallowed unlock + * - the user allows unlock in settings which calls PDBM.setOemUnlockEnabled() + */ +public class OemLockService extends SystemService { + private Context mContext; + + public OemLockService(Context context) { + super(context); + mContext = context; + } + + @Override + public void onStart() { + publishBinderService(Context.OEM_LOCK_SERVICE, mService); + } + + private boolean doIsOemUnlockAllowedByCarrier() { + return !UserManager.get(mContext).hasUserRestriction(UserManager.DISALLOW_OEM_UNLOCK); + } + + private boolean doIsOemUnlockAllowedByUser() { + final PersistentDataBlockManager pdbm = (PersistentDataBlockManager) + mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); + + final long token = Binder.clearCallingIdentity(); + try { + return pdbm.getOemUnlockEnabled(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Implements the binder interface for the service. + */ + private final IBinder mService = new IOemLockService.Stub() { + @Override + public void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) { + enforceManageCarrierOemUnlockPermission(); + enforceUserIsAdmin(); + + // Note: this implementation does not require a signature + + // Continue using user restriction for backwards compatibility + final UserHandle userHandle = UserHandle.of(UserHandle.getCallingUserId()); + final long token = Binder.clearCallingIdentity(); + try { + UserManager.get(mContext) + .setUserRestriction(UserManager.DISALLOW_OEM_UNLOCK, !allowed, userHandle); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public boolean isOemUnlockAllowedByCarrier() { + enforceManageCarrierOemUnlockPermission(); + return doIsOemUnlockAllowedByCarrier(); + } + + @Override + public void setOemUnlockAllowedByUser(boolean allowedByUser) { + if (ActivityManager.isUserAMonkey()) { + // Prevent a monkey from changing this + return; + } + + enforceManageUserOemUnlockPermission(); + enforceUserIsAdmin(); + + final PersistentDataBlockManager pdbm = (PersistentDataBlockManager) + mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); + + final long token = Binder.clearCallingIdentity(); + try { + // The method name is misleading as it really just means whether or not the device + // can be unlocked but doesn't actually do any unlocking. + pdbm.setOemUnlockEnabled(allowedByUser); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public boolean isOemUnlockAllowedByUser() { + enforceManageUserOemUnlockPermission(); + return doIsOemUnlockAllowedByUser(); + } + }; + + private void enforceManageCarrierOemUnlockPermission() { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE, + "Can't manage OEM unlock allowed by carrier"); + } + + private void enforceManageUserOemUnlockPermission() { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE, + "Can't manage OEM unlock allowed by user"); + } + + private void enforceUserIsAdmin() { + final int userId = UserHandle.getCallingUserId(); + final long token = Binder.clearCallingIdentity(); + try { + if (!UserManager.get(mContext).isUserAdmin(userId)) { + throw new SecurityException("Must be an admin user"); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index da49eb37ebec..0613b56e1e47 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -973,6 +973,11 @@ public final class SystemServer { traceBeginAndSlog("StartPersistentDataBlock"); mSystemServiceManager.startService(PersistentDataBlockService.class); traceEnd(); + + // Implementation depends on persistent data block + traceBeginAndSlog("StartOemLockService"); + mSystemServiceManager.startService(OemLockService.class); + traceEnd(); } traceBeginAndSlog("StartDeviceIdleController"); |