/* * 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.oemlock; import android.Manifest; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.oemlock.V1_0.IOemLock; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.UserManagerInternal.UserRestrictionsListener; import android.service.oemlock.IOemLockService; import android.service.persistentdata.PersistentDataBlockManager; import android.util.Slog; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.UserRestrictionsUtils; /** * Service for managing the OEM lock state of the device. * * The OemLock HAL will be used if it is available, otherwise the persistent data block will be * used. */ public class OemLockService extends SystemService { private static final String TAG = "OemLock"; private static final String FLASH_LOCK_PROP = "ro.boot.flash.locked"; private static final String FLASH_LOCK_UNLOCKED = "0"; private Context mContext; private OemLock mOemLock; public static boolean isHalPresent() { return VendorLock.getOemLockHalService() != null; } /** Select the OEM lock implementation */ private static OemLock getOemLock(Context context) { final IOemLock oemLockHal = VendorLock.getOemLockHalService(); if (oemLockHal != null) { Slog.i(TAG, "Using vendor lock via the HAL"); return new VendorLock(context, oemLockHal); } else { Slog.i(TAG, "Using persistent data block based lock"); return new PersistentDataBlockLock(context); } } public OemLockService(Context context) { this(context, getOemLock(context)); } OemLockService(Context context, OemLock oemLock) { super(context); mContext = context; mOemLock = oemLock; LocalServices.getService(UserManagerInternal.class) .addUserRestrictionsListener(mUserRestrictionsListener); } @Override public void onStart() { publishBinderService(Context.OEM_LOCK_SERVICE, mService); } private final UserRestrictionsListener mUserRestrictionsListener = new UserRestrictionsListener() { @Override public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions) { // The admin can prevent OEM unlock with the DISALLOW_FACTORY_RESET user restriction if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, UserManager.DISALLOW_FACTORY_RESET)) { final boolean unlockAllowedByAdmin = !newRestrictions.getBoolean(UserManager.DISALLOW_FACTORY_RESET); if (!unlockAllowedByAdmin) { mOemLock.setOemUnlockAllowedByDevice(false); setPersistentDataBlockOemUnlockAllowedBit(false); } } } }; /** * Implements the binder interface for the service. * * This checks for the relevant permissions before forwarding the call to the OEM lock * implementation being used on this device. */ private final IBinder mService = new IOemLockService.Stub() { @Override public void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) { enforceManageCarrierOemUnlockPermission(); enforceUserIsAdmin(); final long token = Binder.clearCallingIdentity(); try { mOemLock.setOemUnlockAllowedByCarrier(allowed, signature); } finally { Binder.restoreCallingIdentity(token); } } @Override public boolean isOemUnlockAllowedByCarrier() { enforceManageCarrierOemUnlockPermission(); final long token = Binder.clearCallingIdentity(); try { return mOemLock.isOemUnlockAllowedByCarrier(); } finally { Binder.restoreCallingIdentity(token); } } // The user has the final say so if they allow unlock, then the device allows the bootloader // to OEM unlock it. @Override public void setOemUnlockAllowedByUser(boolean allowedByUser) { if (ActivityManager.isUserAMonkey()) { // Prevent a monkey from changing this return; } enforceManageUserOemUnlockPermission(); enforceUserIsAdmin(); final long token = Binder.clearCallingIdentity(); try { if (!isOemUnlockAllowedByAdmin()) { throw new SecurityException("Admin does not allow OEM unlock"); } if (!mOemLock.isOemUnlockAllowedByCarrier()) { throw new SecurityException("Carrier does not allow OEM unlock"); } mOemLock.setOemUnlockAllowedByDevice(allowedByUser); setPersistentDataBlockOemUnlockAllowedBit(allowedByUser); } finally { Binder.restoreCallingIdentity(token); } } @Override public boolean isOemUnlockAllowedByUser() { enforceManageUserOemUnlockPermission(); final long token = Binder.clearCallingIdentity(); try { return mOemLock.isOemUnlockAllowedByDevice(); } finally { Binder.restoreCallingIdentity(token); } } @Override public boolean isOemUnlockAllowed() { enforceOemUnlockReadPermission(); final long token = Binder.clearCallingIdentity(); try { return mOemLock.isOemUnlockAllowedByCarrier() && mOemLock.isOemUnlockAllowedByDevice(); } finally { Binder.restoreCallingIdentity(token); } } @Override public boolean isDeviceOemUnlocked() { enforceOemUnlockReadPermission(); String locked = SystemProperties.get(FLASH_LOCK_PROP); switch (locked) { case FLASH_LOCK_UNLOCKED: return true; default: return false; } } }; /** * Always synchronize the OemUnlockAllowed bit to the FRP partition, which * is used to erase FRP information on a unlockable device. */ private void setPersistentDataBlockOemUnlockAllowedBit(boolean allowed) { final PersistentDataBlockManager pdbm = (PersistentDataBlockManager) mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); // if mOemLock is PersistentDataBlockLock, then the bit should have already been set if (pdbm != null && !(mOemLock instanceof PersistentDataBlockLock)) { Slog.i(TAG, "Update OEM Unlock bit in pst partition to " + allowed); pdbm.setOemUnlockEnabled(allowed); } } private boolean isOemUnlockAllowedByAdmin() { return !UserManager.get(mContext) .hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET, UserHandle.SYSTEM); } 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 enforceOemUnlockReadPermission() { if (mContext.checkCallingOrSelfPermission(Manifest.permission.READ_OEM_UNLOCK_STATE) == PackageManager.PERMISSION_DENIED && mContext.checkCallingOrSelfPermission(Manifest.permission.OEM_UNLOCK_STATE) == PackageManager.PERMISSION_DENIED) { throw new SecurityException("Can't access OEM unlock state. Requires " + "READ_OEM_UNLOCK_STATE or OEM_UNLOCK_STATE permission."); } } 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); } } }