/*
|
* 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.util.Slog;
|
|
import com.android.server.LocalServices;
|
import com.android.server.PersistentDataBlockManagerInternal;
|
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
|
@Nullable
|
public String getLockName() {
|
enforceManageCarrierOemUnlockPermission();
|
|
final long token = Binder.clearCallingIdentity();
|
try {
|
return mOemLock.getLockName();
|
} finally {
|
Binder.restoreCallingIdentity(token);
|
}
|
}
|
|
@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);
|
}
|
}
|
|
/** Currently MasterClearConfirm will call isOemUnlockAllowed()
|
* to sync PersistentDataBlockOemUnlockAllowedBit which
|
* is needed before factory reset
|
* TODO: Figure out better place to run sync e.g. adding new API
|
*/
|
@Override
|
public boolean isOemUnlockAllowed() {
|
enforceOemUnlockReadPermission();
|
|
final long token = Binder.clearCallingIdentity();
|
try {
|
boolean allowed = mOemLock.isOemUnlockAllowedByCarrier()
|
&& mOemLock.isOemUnlockAllowedByDevice();
|
setPersistentDataBlockOemUnlockAllowedBit(allowed);
|
return allowed;
|
} 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 PersistentDataBlockManagerInternal pdbmi
|
= LocalServices.getService(PersistentDataBlockManagerInternal.class);
|
// if mOemLock is PersistentDataBlockLock, then the bit should have already been set
|
if (pdbmi != null && !(mOemLock instanceof PersistentDataBlockLock)) {
|
Slog.i(TAG, "Update OEM Unlock bit in pst partition to " + allowed);
|
pdbmi.forceOemUnlockEnabled(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);
|
}
|
}
|
}
|