在测试CTS Verifier测试的时候,有一项为开发者选项"OEM unlocking"功能,测试的时候需要人为进行判断是否成功。
测试此项前,需要执行如下动作:
adb shell settings put global hidden_api_policy 1
adb install -r -g CtsVerifier.apk
adb install -r -t CtsEmptyDeviceOwner.apk
adb shell dpm set-device-owner com.android.cts.emptydeviceowner/.EmptyDeviceAdmin
然后进入开发者选项,查看OEM unlocking选项后面,是否会弹出一个“!”的图标,点击会弹出一个动画框,能否弹出对话框是根据设备是否已lock来判断的。在bootloader中执行fastboot flashing lock后,此项就可以通过了。
查看lock和unlocked时的系统属性,
$ getprop |grep lock
[cache_key.is_user_unlocked]: [8110559973390150548]
[ro.boot.flash.locked]: [1]
[ro.boot.vbmeta.device_state]: [locked]
[ro.frp.pst]: [/dev/block/bootdevice/by-name/frp]
[ro.oem_unlock_supported]: [1]
[sys.oem_unlock_allowed]: [1]
$ getprop |grep lock
[cache_key.is_user_unlocked]: [8110559973390150548]
[ro.boot.flash.locked]: [1]
[ro.boot.vbmeta.device_state]: [locked]
[ro.frp.pst]: [/dev/block/bootdevice/by-name/frp]
[ro.oem_unlock_supported]: [1]
[sys.oem_unlock_allowed]: [0]
带着这个问题,我们看一下OEM unlocking的内容,主要是根据opengrok跟一下代码的调用过程,内容如下:
settings层===
EnableOemUnlockSettingWarningDialog.java onClick
host.onOemUnlockDialogConfirmed();
|
DevelopmentDashboardFragment.java onOemUnlockDialogConfirmed()
@Override
public void onOemUnlockDialogConfirmed() {
final OemUnlockPreferenceController controller = getDevelopmentOptionsController(
OemUnlockPreferenceController.class);
controller.onOemUnlockConfirmed();
}
|
OemUnlockPreferenceController.java onOemUnlockConfirmed()
public void onOemUnlockConfirmed() {
mOemLockManager.setOemUnlockAllowedByUser(true);
}
|
framework层===
OemLockManager.java setOemUnlockAllowedByUser
mService.setOemUnlockAllowedByUser
|
IOemLockService.aidl setOemUnlockAllowedByUser(boolean allowed)
|
OemLockService.java setOemUnlockAllowedByUser(boolean allowedByUser)
@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);
}
}
/**
* 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);
}
}
|
HW层===
android\hardware\interfaces\oemlock\1.0\IOemLock.hal setOemUnlockAllowedByDevice(bool allowed) generates (OemLockStatus status)
|
android/external/libese/esed/OemLock.cpp OemLock::setOemUnlockAllowedByDevice(bool allowed)
看代码实现,此项应该是留给oem厂商进行定制使用的,开关打开和关闭主要是操作FRP分区,这个分区一般是GMS包版本会用到,比如GMS开机向导中输入的用户账号等信息,都是存在FRP分区中。
当用户在设置中手动执行恢复出厂设置时,在Recovery中一般会清除掉FRP分区信息。用户执行这个恢复出厂设置动作是“可信的”,可以清除FRP分区。
但是当其他形为,比如直接通过命令如adb reboot recovery等或其他途径进入到recovery,是不会清除掉FRP分区的,开机进入到GMS开机向导界面,还是需要用户输入账号等信息的。而且我们这里的oem lock上锁仍然是有效的,数据没有被清除掉。
那么oem unlocking数据是存在哪了呢?
看代码是存在了FRP分区的最后一个block的最后一个BIT比特位上,那是否真是如此呢?
我们可以将FRP分区通过dd命令导出来看一下,命令如下:
dd if=/dev/block/bootdevice/by-name/frp of=/data/data/1.data
在lock和unlock的状态下,分别去dd一下,看下两者有什么不同,下面是我的dd后的效果图:
而且下面两句都是往FRP分区的最后一个bit位操作,只是一个是hal对象的方式,一个是通过PersistentDataBlockManagerInternal API接口去操作的;hal的方式留出来是为了将来厂商进行定制使用。
OemLockService.java setOemUnlockAllowedByUser(boolean allowedByUser)
@Override
public void setOemUnlockAllowedByUser(boolean allowedByUser) {
...
mOemLock.setOemUnlockAllowedByDevice(allowedByUser);
setPersistentDataBlockOemUnlockAllowedBit(allowedByUser);
}
我的理解大概就是这样,仅供参考。