码迷,mamicode.com
首页 > 其他好文 > 详细

oemlock hal

时间:2021-05-24 09:28:04      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:find   require   last   dog   iss   hid   osi   include   add   

概述

OEM锁可以禁止用户刷新bootloader或设备分区,运营商和设备本身都对是否允许OEM解锁有发言权,并且双方都必须同意允许这样做才能使解锁成为可能。

1. oemlock hal的接口

// 返回HAL的vendor特定标识符。
// 返回的名称不能由框架解释,而必须传递给vendor的代码,vendor的代码可以使用它来标识setOemUnlockAllowedByCarrier使用的安全协议。这使供应商无需维护设备到协议的映射即可识别协议。
// 返回值name表示实现的名字
1. getName()

// 更新运营商是否允许oem unlock
// 该实现可能需要供应商定义的签名来证明此请求的有效性,以增强其安全性。
// 参数allowed:flag的新值
// 参数signature:签名以证明此请求的有效性;如果不需要,则为空。
// 返回值status:如果成功更新了标志,则状态为OK;如果需要签名,但提供了错误的签名,则状态为INVALID_SIGNATURE;否则,如果更新失败,则状态为FAILED。
2. setOemUnlockAllowedByCarrier(bool allowed, vec<uint8_t> signature)

// 返回运营商是否已经允许oem unlock了
// 返回值status:如果flag被成功读取,则为OK
// 返回值allowed:flag现在的状态
3. isOemUnlockAllowedByCarrier()

// 更新设备是否允许oem unlock
// 参数allowed:flag的新值
// 返回值status:如果flag被成功更新,则为OK
    frp设1,并算sha-256写进去就可以了
4. setOemUnlockAllowedByDevice(bool allowed)

// 返回设备是否已经允许oem unlock了
// 返回值status:如果flag被成功读取,则为OK
// 返回值allowed:flag现在的状态
    读frp是否为1
5. isOemUnlockAllowedByDevice()

源码解析

1. Settings源码解析

android/packages/apps/Settings/src/com/android/settings/development/OemUnlockPreferenceController.java

主要问题是开发者选项中,oemunlock选项为灰色

1.1 updateState -- oemunlock选项为灰色

    @Override
    protected void onDeveloperOptionsSwitchEnabled() {
        handleDeveloperOptionsToggled();
    }

    private void handleDeveloperOptionsToggled() {
        // 打开开发者选项的时候,也会判断是否要设为灰色(已经unlock的就为灰色了),no_oem_unlock=true也为灰色
        mPreference.setEnabled(enableOemUnlockPreference());
        if (mPreference.isEnabled()) {
            // Check restriction, disable mEnableOemUnlock and apply policy transparency.
            mPreference.checkRestrictionAndSetDisabled(UserManager.DISALLOW_FACTORY_RESET);
        }
    }

@Override
    public void updateState(Preference preference) {
        super.updateState(preference);
        // oemunlock选项是否已经unlocked了。unlocked的话,这里返回true
        mPreference.setChecked(isOemUnlockedAllowed());
        updateOemUnlockSettingDescription();
        // Showing mEnableOemUnlock preference as device has persistent data block.
        mPreference.setDisabledByAdmin(null);
        // oemunlock 选项是否要设为灰色(已经unlock的就为灰色了)
        mPreference.setEnabled(enableOemUnlockPreference());
        if (mPreference.isEnabled()) {
            // Check restriction, disable mEnableOemUnlock and apply policy transparency.
            mPreference.checkRestrictionAndSetDisabled(UserManager.DISALLOW_FACTORY_RESET);
        }
    }

1.2 enableOemUnlockPreference -- 灰色

    private boolean enableOemUnlockPreference() {
        // 判断设备是否已经unlock了,已经unlock则直接返回true,所以已经unlock了的话,这个preference是灰色的
        // 如果在overlay中配置了config_defaultFirstUserRestrictions的话,no_oem_unlock=true,对应
        // 联网之后,no_oem_unlock就被设为false了,然后开发者选项中就不为灰色了
        return !isBootloaderUnlocked() && isOemUnlockAllowedByUserAndCarrier();
    }

1.3 isBootloaderUnlocked

	boolean isBootloaderUnlocked() {
        // 判断是否已经unlock了,判断ro.boot.flash.locked属性是否为0,为0则是unlock的,unlock则返回true;为1就是locked的(false)
        return mOemLockManager.isDeviceOemUnlocked();
    }

1.4 isOemUnlockAllowedByUserAndCarrier

    boolean isOemUnlockAllowedByUserAndCarrier() {
        final UserHandle userHandle = UserHandle.of(UserHandle.myUserId());
        // 这里返回true
        return mOemLockManager.isOemUnlockAllowedByCarrier()
            // 这里一般是true的
                && !mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_FACTORY_RESET,
                userHandle);
    }

1.5 isOemUnlockedAllowed

    @VisibleForTesting
    boolean isOemUnlockedAllowed() {
        return mOemLockManager.isOemUnlockAllowed();
    }

1.6 onPreferenceChange -- 开发者选项打开oemlock选项

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean isUnlocked = (Boolean) newValue;
        if (isUnlocked) {
            if (!showKeyguardConfirmation(mContext.getResources(),
                    REQUEST_CODE_ENABLE_OEM_UNLOCK)) {
                // 弹出提示框,然后enable的话,就往frp分区写1
                confirmEnableOemUnlock();
            }
        } else {
            mOemLockManager.setOemUnlockAllowedByUser(false);
            OemLockInfoDialog.show(mFragment);
        }
        return true;
    }

1.7 confirmEnableOemUnlock

    @VisibleForTesting
    void confirmEnableOemUnlock() {
        EnableOemUnlockSettingWarningDialog.show(mFragment);
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        final OemUnlockDialogHost host = (OemUnlockDialogHost) getTargetFragment();
        if (host == null) {
            return;
        }
        if (which == DialogInterface.BUTTON_POSITIVE) {
            host.onOemUnlockDialogConfirmed();
        } else {
            host.onOemUnlockDialogDismissed();
        }
    }

1.8 onOemUnlockDialogConfirmed

    @Override
    public void onOemUnlockDialogConfirmed() {
        final OemUnlockPreferenceController controller = getDevelopmentOptionsController(
                OemUnlockPreferenceController.class);
        controller.onOemUnlockConfirmed();
    }

1.9 onOemUnlockConfirmed

    public void onOemUnlockConfirmed() {
        // oemlock hal写1
        // frp分区写1。两步都会去做
        mOemLockManager.setOemUnlockAllowedByUser(true);
    }

2. OemLockManager

2.1 run - SystemServer

frameworks/base/services/java/com/android/server/SystemServer.java

    private void run() {
        TimingsTraceAndSlog t = new TimingsTraceAndSlog();
        try {
            .....
            SystemServiceRegistry.sEnableServiceNotFoundWtf = true;
            ....
        }
    }

2.2 SystemServiceRegistry - static代码块

// 类被加载了不一定就会执行静态代码块,只有一个类被主动使用的时候,静态代码才会被执行!类被调用了,才会调用static代码块
static {
        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;
                }
            }});
}

2.3 isDeviceOemUnlocked

OemLockManager的函数调用都是调用OemLockService里面去的,oemlockmanager只是个接口

    public boolean isDeviceOemUnlocked() {
        try {
            return mService.isDeviceOemUnlocked();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

3. OemLockService

/frameworks/base/services/core/java/com/android/server/oemlock/OemLockService.java

3.1 isDeviceOemUnlocked

        @Override
        public boolean isDeviceOemUnlocked() {
            enforceOemUnlockReadPermission();

            String locked = SystemProperties.get(FLASH_LOCK_PROP);
            switch (locked) {
                   // 这个是0,返回的是true
                case FLASH_LOCK_UNLOCKED:
                    return true;
                default:
                    return false;
            }
        }

3.2 构造函数

    private static OemLock getOemLock(Context context) {
        final IOemLock oemLockHal = VendorLock.getOemLockHalService();
        // 是否使用oemlock hal;如果使用了oemlock hal,则使用oemlock hal
        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");
            //否则的话,就使用PersistentDataBlockLock
            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);
    }

3.3 isOemUnlockAllowedByCarrier

        @Override
        public boolean isOemUnlockAllowedByCarrier() {
            enforceManageCarrierOemUnlockPermission();

            final long token = Binder.clearCallingIdentity();
            try {
              return mOemLock.isOemUnlockAllowedByCarrier();
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

3.4 isOemUnlockAllowed

        /** 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 {
                // no_oem_unlock=false;所以isOemUnlockAllowedByCarrier为true
                boolean allowed = mOemLock.isOemUnlockAllowedByCarrier()
                    // 所以主要看isOemUnlockAllowedByDevice:读/dev/block/by-name/frp分区的最后一位,看是否为1,为1则返回true
                        && mOemLock.isOemUnlockAllowedByDevice();
                // 往frp分区最后一位写allowed
                setPersistentDataBlockOemUnlockAllowedBit(allowed);
                return allowed;
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

3.5 setOemUnlockAllowedByUser

        // 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");
                }

                // 如果用的是persistentdata的话,下面两个函数都是一样的功能,都是往frp分区写1
                mOemLock.setOemUnlockAllowedByDevice(allowedByUser);
                // 往frp分区写1
                setPersistentDataBlockOemUnlockAllowedBit(allowedByUser);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

4. PersistentDataBlockLock

framework/base/services/core/java/com/android/server/oemlock/PersistentDataBlockLock.java

4.1 isOemUnlockAllowedByCarrier

    @Override
// no_oem_unlock=true则返回false;no_oem_unlock=false则返回true
    boolean isOemUnlockAllowedByCarrier() {
        return !UserManager.get(mContext)
                .hasUserRestriction(UserManager.DISALLOW_OEM_UNLOCK, UserHandle.SYSTEM);
    }

4.2 isOemUnlockAllowedByDevice

    @Override
    boolean isOemUnlockAllowedByDevice() {
        final PersistentDataBlockManager pdbm = (PersistentDataBlockManager)
            mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
        if (pdbm == null) {
            Slog.w(TAG, "PersistentDataBlock is not supported on this device");
            return false;
        }
        return pdbm.getOemUnlockEnabled();
    }

4.3 setOemUnlockAllowedByDevice

    @Override
    void setOemUnlockAllowedByDevice(boolean allowedByDevice) {
        // 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.
        final PersistentDataBlockManager pdbm = (PersistentDataBlockManager)
                mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
        if (pdbm == null) {
            Slog.w(TAG, "PersistentDataBlock is not supported on this device");
            return;
        }
        pdbm.setOemUnlockEnabled(allowedByDevice);
    }

5. UserManager

android/frameworks/base/core/java/android/os/UserManager.java

5.1 hasUserRestriction

    @UnsupportedAppUsage
    public boolean hasUserRestriction(@UserRestrictionKey String restrictionKey,
            UserHandle userHandle) {
        return hasUserRestrictionForUser(restrictionKey, userHandle);
    }

    @SystemApi
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MANAGE_USERS,
            android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
    public boolean hasUserRestrictionForUser(@NonNull @UserRestrictionKey String restrictionKey,
            @NonNull UserHandle userHandle) {
        try {
            return mService.hasUserRestriction(restrictionKey, userHandle.getIdentifier());
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

6. UserManagerService

frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java

6.1 hasUserRestriction

    /** @return a specific user restriction that‘s in effect currently. */
    @Override
    public boolean hasUserRestriction(String restrictionKey, @UserIdInt int userId) {
        checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId, "hasUserRestriction");
        return mLocalService.hasUserRestriction(restrictionKey, userId);
    }

        @Override
        public boolean hasUserRestriction(String restrictionKey, @UserIdInt int userId) {
            // 检查是否有这个restrictionKey,里面有一个USER_RESTRICTIONS集合,包含所有的restrictionKey
            // 经查看,是有DISALLOW_OEM_UNLOCK这个key的
            if (!UserRestrictionsUtils.isValidRestriction(restrictionKey)) {
                return false;
            }
            Bundle restrictions = getEffectiveUserRestrictions(userId);
            // 获取key的值
            return restrictions != null && restrictions.getBoolean(restrictionKey);
        }

6.2 restrictionKey的更新流程 - 第一次开机

调用栈:
UserManagerService: writeUserLP com.android.server.pm.UserManagerService$UserData@d9662bc called at
UserManagerService:   com.android.server.pm.UserManagerService.writeUserLP:2823
UserManagerService:   com.android.server.pm.UserManagerService.fallbackToSingleUserLP:2791
UserManagerService:   com.android.server.pm.UserManagerService.readUserListLP:2496
UserManagerService:   com.android.server.pm.UserManagerService.<init>:624
UserManagerService:   com.android.server.pm.UserManagerService.<init>:602
UserManagerService:   com.android.server.pm.PackageManagerService.lambda$main$2:2595
UserManagerService:   com.android.server.pm.-$$Lambda$PackageManagerService$xKD6SB7pISjc29qfmXIq5O_3OJw.produce:12
UserManagerService:   com.android.server.pm.PackageManagerService$Injector$Singleton.get:910
UserManagerService:   com.android.server.pm.PackageManagerService$Injector.getUserManagerService:1004
UserManagerService:   com.android.server.pm.PackageManagerService.<init>:2871
6.2.1 fallbackToSingleUserLP
    @GuardedBy({"mPackagesLock", "mRestrictionsLock"})
    private void fallbackToSingleUserLP() {
        int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN
                | UserInfo.FLAG_PRIMARY;
        // Create the system user
        String systemUserType = UserManager.isHeadlessSystemUserMode() ?
                UserManager.USER_TYPE_SYSTEM_HEADLESS : UserManager.USER_TYPE_FULL_SYSTEM;
        flags |= mUserTypes.get(systemUserType).getDefaultUserInfoFlags();
        UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags, systemUserType);
        UserData userData = putUserInfo(system);
        mNextSerialNumber = MIN_USER_ID;
        mUserVersion = USER_VERSION;
        mUserTypeVersion = UserTypeFactory.getUserTypeVersion();

        Bundle restrictions = new Bundle();
        try {
            // 在这里会解析config_defaultFirstUserRestrictions配置
            final String[] defaultFirstUserRestrictions = mContext.getResources().getStringArray(
                    com.android.internal.R.array.config_defaultFirstUserRestrictions);
            for (String userRestriction : defaultFirstUserRestrictions) {
                if (UserRestrictionsUtils.isValidRestriction(userRestriction)) {
                    // 然后给他写上true,所以no_oem_unlock=true
                    restrictions.putBoolean(userRestriction, true);
                }
            }
        } catch (Resources.NotFoundException e) {
            Slog.e(LOG_TAG, "Couldn‘t find resource: config_defaultFirstUserRestrictions", e);
        }

        if (!restrictions.isEmpty()) {
            synchronized (mRestrictionsLock) {
                mBaseUserRestrictions.updateRestrictions(UserHandle.USER_SYSTEM,
                        restrictions);
            }
        }

        updateUserIds();
        initDefaultGuestRestrictions();

        // 然后这里写到了/data/system/users/0.xml文件
        writeUserLP(userData);
        writeUserListLP();
    }
6.2.2 /data/system/users/0.xml文件
<?xml version=‘1.0‘ encoding=‘utf-8‘ standalone=‘yes‘ ?>
<user id="0" serialNumber="0" flags="3091" type="android.os.usertype.full.SYSTEM" created="0" lastLoggedIn="1620875315872" lastLoggedInFingerprint="Allwinner/ceres_b4/ceres-b4:11/RP1A.201005.006/eng.xx.20210512.114843:userdebug/test-keys" profileBadge="0">
    <restrictions no_oem_unlock="true" />
    <device_policy_local_restrictions />
</user>

6.3 restrictionKey的更新流程 - GMS core包更新

调用栈:

UserManagerService: scheduleWriteUser called at
UserManagerService:   com.android.server.pm.UserManagerService.scheduleWriteUser:2801
UserManagerService:   com.android.server.pm.UserManagerService.updateUserRestrictionsInternalLR:2104
UserManagerService:   com.android.server.pm.UserManagerService.setUserRestriction:2076
UserManagerService:   android.os.IUserManager$Stub.onTransact:1165
UserManagerService:   android.os.Binder.execTransactInternal:1154
UserManagerService:   android.os.Binder.execTransact:1123
UserManagerService:   <bottom of call stack>
UserManagerService:   <bottom of call stack>
UserManagerService:   <bottom of call stack>
UserManagerService:   <bottom of call stack>
UserManagerService: Applying user restrictions: userId=0 new=Bundle[{no_oem_unlock=false}] prev=Bundle[{no_oem_unlock=true}] called at
UserManagerService:   com.android.server.pm.UserManagerService.updateUserRestrictionsInternalLR:2114
UserManagerService:   com.android.server.pm.UserManagerService.setUserRestriction:2076
UserManagerService:   android.os.IUserManager$Stub.onTransact:1165
UserManagerService:   android.os.Binder.execTransactInternal:1154
UserManagerService:   android.os.Binder.execTransact:1123
UserManagerService:   <bottom of call stack>
UserManagerService:   <bottom of call stack>
UserManagerService:   <bottom of call stack>
UserManagerService:   <bottom of call stack>
UserManagerService:   <bottom of call stack>
UserManagerService: writeUserLP com.android.server.pm.UserManagerService$UserData@d9662bc called at
UserManagerService:   com.android.server.pm.UserManagerService.writeUserLP:2823
UserManagerService:   com.android.server.pm.UserManagerService.access$1500:155
UserManagerService:   com.android.server.pm.UserManagerService$MainHandler.handleMessage:4843
UserManagerService:   android.os.Handler.dispatchMessage:106
UserManagerService:   android.os.Looper.loop:223
UserManagerService:   com.android.server.SystemServer.run:644
UserManagerService:   com.android.server.SystemServer.main:419
UserManagerService:   java.lang.reflect.Method.invoke:-2
UserManagerService:   com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run:592
UserManagerService:   com.android.internal.os.ZygoteInit.main:1062

大概的流程就是:

联网 -> GMS Core app调用setUserRestriction接口,设置no_oem_unlock=false -> updateUserRestrictionsInternalLR -> scheduleWriteUser -> writeUserLP:写到/data/system/users/0.xml文件

7. PersistentDataBlockService

frameworks/base/services/core/java/com/android/server/PersistentDataBlockService.java

7.1 getOemUnlockEnabled

        @Override
        public boolean getOemUnlockEnabled() {
            enforceOemUnlockReadPermission();
            return doGetOemUnlockEnabled();
        }

7.2 doGetOemUnlockEnabled

    private boolean doGetOemUnlockEnabled() {
        DataInputStream inputStream;
        try {
            // 读"ro.frp.pst"属性:/dev/block/by-name/frp
            inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
        } catch (FileNotFoundException e) {
            Slog.e(TAG, "partition not available");
            return false;
        }

        try {
            synchronized (mLock) {
                // 读/dev/block/by-name/frp分区的最后一位,看是否为1,为1则返回true
                inputStream.skip(getBlockDeviceSize() - 1);
                return inputStream.readByte() != 0;
            }
        } catch (IOException e) {
            Slog.e(TAG, "unable to access persistent partition", e);
            return false;
        } finally {
            IoUtils.closeQuietly(inputStream);
        }
    }

7.3 setOemUnlockEnabled

        @Override
        public void setOemUnlockEnabled(boolean enabled) throws SecurityException {
            // do not allow monkey to flip the flag
            if (ActivityManager.isUserAMonkey()) {
                return;
            }

            enforceOemUnlockWritePermission();
            enforceIsAdmin();

            if (enabled) {
                // Do not allow oem unlock to be enabled if it‘s disallowed by a user restriction.
                enforceUserRestriction(UserManager.DISALLOW_OEM_UNLOCK);
                enforceUserRestriction(UserManager.DISALLOW_FACTORY_RESET);
            }
            synchronized (mLock) {
                // 往frp写1
                doSetOemUnlockEnabledLocked(enabled);
                // 计算digest值
                computeAndWriteDigestLocked();
            }
        }

7.4 frp分区的组成

 * The persistent data block is currently laid out as follows:
 * | ---------BEGINNING OF PARTITION-------------|
 * | Partition digest (32 bytes)                 |
 * | --------------------------------------------|
 * | PARTITION_TYPE_MARKER (4 bytes)             |
 * | --------------------------------------------|
 * | FRP data block length (4 bytes)             |
 * | --------------------------------------------|
 * | FRP data (variable length)                  |
 * | --------------------------------------------|
 * | ...                                         |
 * | --------------------------------------------|
 * | Test mode data block (10000 bytes)          |
 * | --------------------------------------------|
 * |     | Test mode data length (4 bytes)       |
 * | --------------------------------------------|
 * |     | Test mode data (variable length)      |
 * |     | ...                                   |
 * | --------------------------------------------|
 * | FRP credential handle block (1000 bytes)    |
 * | --------------------------------------------|
 * |     | FRP credential handle length (4 bytes)|
 * | --------------------------------------------|
 * |     | FRP credential handle (variable len)  |
 * |     | ...                                   |
 * | --------------------------------------------|
 * | OEM Unlock bit (1 byte)                     |
 * | ---------END OF PARTITION-------------------|
 // 最后一位就是oem unlock bit

7.5 doSetOemUnlockEnabledLocked

    private void doSetOemUnlockEnabledLocked(boolean enabled) {
        FileOutputStream outputStream;
        try {
            outputStream = getBlockOutputStream();
        } catch (IOException e) {
            Slog.e(TAG, "partition not available", e);
            return;
        }

        try {
            FileChannel channel = outputStream.getChannel();

            channel.position(getBlockDeviceSize() - 1);

            ByteBuffer data = ByteBuffer.allocate(1);
            // 这里判断是否为1
            data.put(enabled ? (byte) 1 : (byte) 0);
            data.flip();
            // 往frp分区写
            channel.write(data);
            outputStream.flush();
        } catch (IOException e) {
            Slog.e(TAG, "unable to access persistent partition", e);
            return;
        } finally {
            SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
            IoUtils.closeQuietly(outputStream);
        }
    }

7.6 computeAndWriteDigestLocked

    private boolean computeAndWriteDigestLocked() {
        byte[] digest = computeDigestLocked(null);
        if (digest != null) {
            DataOutputStream outputStream;
            try {
                outputStream = new DataOutputStream(getBlockOutputStream());
            } catch (IOException e) {
                Slog.e(TAG, "partition not available?", e);
                return false;
            }

            try {
                // 写digest
                outputStream.write(digest, 0, DIGEST_SIZE_BYTES);
                outputStream.flush();
            } catch (IOException e) {
                Slog.e(TAG, "failed to write block checksum", e);
                return false;
            } finally {
                IoUtils.closeQuietly(outputStream);
            }
            return true;
        } else {
            return false;
        }
    }

// 计算digest
    private byte[] computeDigestLocked(byte[] storedDigest) {
        DataInputStream inputStream;
        try {
            inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
        } catch (FileNotFoundException e) {
            Slog.e(TAG, "partition not available?", e);
            return null;
        }

        MessageDigest md;
        try {
            md = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e) {
            // won‘t ever happen -- every implementation is required to support SHA-256
            Slog.e(TAG, "SHA-256 not supported?", e);
            IoUtils.closeQuietly(inputStream);
            return null;
        }

        try {
            if (storedDigest != null && storedDigest.length == DIGEST_SIZE_BYTES) {
                inputStream.read(storedDigest);
            } else {
                inputStream.skipBytes(DIGEST_SIZE_BYTES);
            }

            int read;
            byte[] data = new byte[1024];
            md.update(data, 0, DIGEST_SIZE_BYTES); // include 0 checksum in digest
            while ((read = inputStream.read(data)) != -1) {
                md.update(data, 0, read);
            }
        } catch (IOException e) {
            Slog.e(TAG, "failed to read partition", e);
            return null;
        } finally {
            IoUtils.closeQuietly(inputStream);
        }

        return md.digest();
    }

oemlock hal实现

实现的版本也是往frp写1

#include <openssl/sha.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include "OemLockHidl.h"

namespace android {
namespace hardware {
namespace oemlock {
namespace V1_0 {
namespace implementation {

using ::android::base::ParseInt;
using ::android::base::ReadFileToString;
using ::android::base::ReadFullyAtOffset;
using ::android::base::Split;
using ::android::base::StringPrintf;
using ::android::base::unique_fd;

const std::string FRP_DEV_PATH = "/dev/block/by-name/frp";
#define DIGEST_SIZE_BYTES 32

static int64_t get_file_size(int fd) {
    struct stat buf;
    int ret = fstat(fd, &buf);
    if (ret) return 0;

    int64_t computed_size = 0;
    if (S_ISREG(buf.st_mode)) {
        computed_size = buf.st_size;
    } else if (S_ISBLK(buf.st_mode)) {
        uint64_t block_device_size = 0;
        ret = ioctl(fd, BLKGETSIZE64, &block_device_size);
        if (ret) return 0;
        computed_size = block_device_size;
    }

    LOG(INFO) << "oemlock_impl get file size " << computed_size;
    return computed_size;
}

Return<void> OemLockHidl::getName(getName_cb _hidl_cb)
{
    OemLockStatus status = OemLockStatus::OK;
    hidl_string name = "oemlock";
    _hidl_cb(status, name);
    return Void();
}

Return<OemLockSecureStatus> OemLockHidl::setOemUnlockAllowedByCarrier(bool allowed, const hidl_vec<uint8_t>& signature)
{
    (void)allowed;
    (void)signature;
    OemLockSecureStatus status = OemLockSecureStatus::OK;
    return status;
}

Return<void> OemLockHidl::isOemUnlockAllowedByCarrier(isOemUnlockAllowedByCarrier_cb _hidl_cb)
{
    bool allowed = true;
    OemLockStatus status = OemLockStatus::OK;
    _hidl_cb(status, allowed);
    return Void();
}

OemLockHidl::OemLockHidl() {}

}  // namespace implementation
}  // namespace V1_0
}  // namespace oemlock
}  // namespace hardware
}  // namespace androi

1. setOemUnlockAllowedByDevice

Return<OemLockStatus> OemLockHidl::setOemUnlockAllowedByDevice(bool allowed)
{
    OemLockStatus status = OemLockStatus::OK;
    if (set_oemunlock_allowed_by_device_impl(allowed) < 0) {
        LOG(ERROR) << "oemlock setOemUnlockAllowedByDevice fail";
        status = OemLockStatus::FAILED;
    }
    return status;
}

int do_set_oemunlock_allowed_by_device(bool in_allowed)
{
    unique_fd fd(TEMP_FAILURE_RETRY(open(FRP_DEV_PATH.c_str(), O_WRONLY | O_CLOEXEC | O_BINARY)));
    if (fd < 0) {
        LOG(ERROR) << "oemlock do_set_oemunlock_allowed_by_device open file fail";
        return -1;
    }
    int64_t offset = get_file_size(fd) - 1;
    if (offset < 0) {
        LOG(ERROR) << "oemlock do_set_oemunlock_allowed_by_device get_file_size fail";
        return -1;
    }
    LOG(INFO) << "oemlock_impl write oem unlock flag offset " << offset;
    uint8_t flag = in_allowed ? (uint8_t) 1 : (uint8_t) 0;
    LOG(INFO) << "oemlock_impl write oem unlock flag is " << flag;
    if (lseek(fd, offset, SEEK_SET) < 0) {
        LOG(ERROR) << "oemlock do_set_oemunlock_allowed_by_device lseek fail";
        return -1;
    }
    if (write(fd, &flag, 1) < 0) {
        LOG(ERROR) << "oemlock do_set_oemunlock_allowed_by_device write fail";
        return -1;
    }
    return 0;
}

int compute_and_write_digest()
{
    unique_fd fd(TEMP_FAILURE_RETRY(open(FRP_DEV_PATH.c_str(), O_RDWR | O_CLOEXEC | O_BINARY)));
    if (fd < 0) {
        LOG(ERROR) << "oemlock compute_and_write_digest open file fail";
        return -1;
    }
    int64_t data_size = get_file_size(fd) - DIGEST_SIZE_BYTES;
    if (data_size < 0) {
        LOG(ERROR) << "oemlock compute_and_write_digest get_file_size fail";
        return -1;
    }
    std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(data_size);
    std::unique_ptr<uint8_t[]> digest = std::make_unique<uint8_t[]>(DIGEST_SIZE_BYTES);
    if (ReadFullyAtOffset(fd, data.get(), data_size, DIGEST_SIZE_BYTES) < 0) {
        LOG(ERROR) << "oemlock compute_and_write_digest ReadFullyAtOffset fail";
        return -1;
    }
    SHA256_CTX sha256_ctx;
    SHA256_Init(&sha256_ctx);
    SHA256_Update(&sha256_ctx, data.get(), data_size);
    SHA256_Final(digest.get(), &sha256_ctx);
    if (lseek(fd, 0, SEEK_SET) < 0) {
        LOG(ERROR) << "oemlock compute_and_write_digest lseek fail";
        return -1;
    }
    if (write(fd, digest.get(), DIGEST_SIZE_BYTES) < 0) {
        LOG(ERROR) << "oemlock compute_and_write_digest write fail";
        return -1;
    }
    return 0;
}

int set_oemunlock_allowed_by_device_impl(bool in_allowed)
{
    if (do_set_oemunlock_allowed_by_device(in_allowed) < 0) {
        LOG(ERROR) << "oemlock do_set_oemunlock_allowed_by_device fail";
        return -1;
    }
    if (compute_and_write_digest() < 0) {
        LOG(ERROR) << "oemlock compute_and_write_digest fail";
        return -1;
    }
    return 0;
}

1.2 isOemUnlockAllowedByDevice

int is_oemunlock_allowed_by_device_impl(bool *allowed) {
    unique_fd fd(TEMP_FAILURE_RETRY(open(FRP_DEV_PATH.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY)));
    if (fd < 0) {
        LOG(ERROR) << "oemlock is_oemunlock_allowed_by_device_impl open file fail";
        return -1;
    }
    int64_t offset = get_file_size(fd) - 1;
    if (offset < 0) {
        LOG(ERROR) << "oemlock is_oemunlock_allowed_by_device_impl get_file_size fail";
        return -1;
    }
    LOG(INFO) << "oemlock_impl read oem unlock flag offset " << offset;
    int flag;
    if (ReadFullyAtOffset(fd, &flag, 1, offset) < 0) {
        LOG(ERROR) << "oemlock is_oemunlock_allowed_by_device_impl ReadFullyAtOffset fail";
        return -1;
    }
    LOG(INFO) << "oemlock_impl read oem unlock flag is " << flag;
    *allowed = (flag == 1) ? true : false;
    return 0;
}
Return<void> OemLockHidl::isOemUnlockAllowedByDevice(isOemUnlockAllowedByDevice_cb _hidl_cb)
{
    OemLockStatus status = OemLockStatus::OK;
    bool allowed = false;
    if (is_oemunlock_allowed_by_device_impl(&allowed) < 0) {
        LOG(ERROR) << "oemlock isOemUnlockAllowedByDevice fail";
        status = OemLockStatus::FAILED;
    }
    _hidl_cb(status, allowed);
    return Void();
}

问题

1. 开发者选项中,oemunlock选项为灰色

由于GMS要求,要把config_defaultFirstUserRestrictions配置为no_oem_unlock,所以开发者选项为灰色

由于oemlock hal不能写frp分区(selinux neverallow规则),所以没办法实现oemlock hal写frp分区

所以暂时去掉config_defaultFirstUserRestrictions配置,让机器不用联网,就可以在开发者选项中打开oemlock选项

diff --git a/common/overlay/overlay/frameworks/base/core/res/res/values/config.xml b/common/overlay/overlay/frameworks/base/core/res/res/values/config.xml
old mode 100644
new mode 100755
index 61ca324..be9a5b0
--- a/common/overlay/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/common/overlay/overlay/frameworks/base/core/res/res/values/config.xml
@@ -718,4 +718,11 @@
     </array>
 
     <bool name="config_shutdownForceScreenOff">true</bool>
+
+    <!-- Package name for the device provisioning package. -->
+    <string name="config_deviceProvisioningPackage">com.google.android.apps.work.oobconfig</string>
+
+    <string-array translatable="false" name="config_defaultFirstUserRestrictions">
+    <item>"no_oem_unlock"</item>
+    </string-array>
 </resources>

参考

1. android去除安全模式
https://blog.csdn.net/qq_28534581/article/details/84885773
2. Android Verified Boot浅知分享
https://www.jianshu.com/p/d354280f1f27

oemlock hal

标签:find   require   last   dog   iss   hid   osi   include   add   

原文地址:https://www.cnblogs.com/pyjetson/p/14769333.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!