Add implementation alternatives for OemLockManager.

The OEM lock can be implemented with the persistent data block or the
OemLock HAL.

Test: gts-tradefed run gts -m GtsOemLockServiceTestCases -t com.google.android.oemlock.gts.OemLockServiceTest
Bug: 34766843
Change-Id: I16b31785d9af58212a050a299ef024be3139f0c6
diff --git a/core/java/android/service/oemlock/IOemLockService.aidl b/core/java/android/service/oemlock/IOemLockService.aidl
index 2c606f9..682e7ee 100644
--- a/core/java/android/service/oemlock/IOemLockService.aidl
+++ b/core/java/android/service/oemlock/IOemLockService.aidl
@@ -27,4 +27,8 @@
 
     void setOemUnlockAllowedByUser(boolean allowed);
     boolean isOemUnlockAllowedByUser();
+
+    boolean canUserAllowOemUnlock();
+    boolean isOemUnlockAllowed();
+    boolean isDeviceOemUnlocked();
 }
diff --git a/core/java/android/service/oemlock/OemLockManager.java b/core/java/android/service/oemlock/OemLockManager.java
index c4fbe5e..9e69362 100644
--- a/core/java/android/service/oemlock/OemLockManager.java
+++ b/core/java/android/service/oemlock/OemLockManager.java
@@ -82,7 +82,8 @@
      *
      * All actors involved must agree for OEM unlock to be possible.
      *
-     * @param unlocked Whether the device should be made OEM unlocked.
+     * @param allowed Whether the device should be allowed to be unlocked.
+     * @throws SecurityException if the user is not allowed to unlock the device.
      *
      * @see #isOemUnlockAllowedByUser()
      */
@@ -107,4 +108,48 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Returns whether all parties other than the user allow OEM unlock meaning the user can
+     * directly control whether or not the device can be OEM unlocked.
+     *
+     * If this is true, {@link #isOemUnlockAllowedByUser} is the same as {@link #isOemUnlockAllowed}
+     *
+     * @return Whether the user can directly control whether the device can be OEM unlocked.
+     *
+     * @hide
+     */
+    public boolean canUserAllowOemUnlock() {
+        try {
+            return mService.canUserAllowOemUnlock();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @return Whether the bootloader is able to OEM unlock the device.
+     *
+     * @hide
+     */
+    public boolean isOemUnlockAllowed() {
+        try {
+            return mService.isOemUnlockAllowed();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @return Whether the device has been OEM unlocked by the bootloader.
+     *
+     * @hide
+     */
+    public boolean isDeviceOemUnlocked() {
+        try {
+            return mService.isOemUnlockAllowed();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 7f07f03..22d7541 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -229,6 +229,7 @@
         <permission name="android.permission.MANAGE_FINGERPRINT"/>
         <permission name="android.permission.MANAGE_USB"/>
         <permission name="android.permission.MANAGE_USERS"/>
+        <permission name="android.permission.MANAGE_USER_OEM_UNLOCK_STATE" />
         <permission name="android.permission.MASTER_CLEAR"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
diff --git a/services/core/Android.mk b/services/core/Android.mk
index f896478..94a3e0a 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -30,6 +30,7 @@
     tzdata_update2 \
     android.hidl.base-V1.0-java-static \
     android.hardware.biometrics.fingerprint-V2.1-java-static \
+    android.hardware.oemlock-V1.0-java-static \
     android.hardware.vibrator-V1.0-java-constants \
 
 ifneq ($(INCREMENTAL_BUILDS),)
diff --git a/services/core/java/com/android/server/OemLockService.java b/services/core/java/com/android/server/OemLockService.java
deleted file mode 100644
index 03f82a8..0000000
--- a/services/core/java/com/android/server/OemLockService.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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/core/java/com/android/server/oemlock/OemLock.java b/services/core/java/com/android/server/oemlock/OemLock.java
new file mode 100644
index 0000000..ee70c29
--- /dev/null
+++ b/services/core/java/com/android/server/oemlock/OemLock.java
@@ -0,0 +1,27 @@
+/*
+ * 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.annotation.Nullable;
+
+abstract class OemLock {
+    abstract void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature);
+    abstract boolean isOemUnlockAllowedByCarrier();
+
+    abstract void setOemUnlockAllowedByDevice(boolean allowedByDevice);
+    abstract boolean isOemUnlockAllowedByDevice();
+}
diff --git a/services/core/java/com/android/server/oemlock/OemLockService.java b/services/core/java/com/android/server/oemlock/OemLockService.java
new file mode 100644
index 0000000..5e19b13
--- /dev/null
+++ b/services/core/java/com/android/server/oemlock/OemLockService.java
@@ -0,0 +1,251 @@
+/*
+ * 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.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);
+                }
+            }
+        }
+    };
+
+    /**
+     * 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 (!canUserAllowOemUnlock()) {
+                    throw new SecurityException("User cannot allow OEM unlock");
+                }
+
+                mOemLock.setOemUnlockAllowedByDevice(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 canUserAllowOemUnlock() {
+            enforceOemUnlockReadPermission();
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return isOemUnlockAllowedByAdmin() && mOemLock.isOemUnlockAllowedByCarrier();
+            } 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;
+            }
+        }
+    };
+
+    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);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/oemlock/PersistentDataBlockLock.java b/services/core/java/com/android/server/oemlock/PersistentDataBlockLock.java
new file mode 100644
index 0000000..d9362d4
--- /dev/null
+++ b/services/core/java/com/android/server/oemlock/PersistentDataBlockLock.java
@@ -0,0 +1,92 @@
+/*
+ * 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.annotation.Nullable;
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.service.persistentdata.PersistentDataBlockManager;
+import android.util.Slog;
+
+/**
+ * Implementation of the OEM lock using the persistent data block to communicate with the
+ * bootloader.
+ *
+ * The carrier flag is stored as a user restriction on the system user. The user flag is set in the
+ * presistent data block but depends on the carrier flag.
+ */
+class PersistentDataBlockLock extends OemLock {
+    private static final String TAG = "OemLock";
+
+    private Context mContext;
+
+    PersistentDataBlockLock(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) {
+        // Note: this implementation does not require a signature
+        if (signature != null) {
+            Slog.w(TAG, "Signature provided but is not being used");
+        }
+
+        // Continue using user restriction for backwards compatibility
+        UserManager.get(mContext).setUserRestriction(
+                UserManager.DISALLOW_OEM_UNLOCK, !allowed, UserHandle.SYSTEM);
+
+        if (!allowed) {
+            disallowUnlockIfNotUnlocked();
+        }
+    }
+
+    @Override
+    boolean isOemUnlockAllowedByCarrier() {
+        return !UserManager.get(mContext)
+                .hasUserRestriction(UserManager.DISALLOW_OEM_UNLOCK, UserHandle.SYSTEM);
+    }
+
+    @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);
+        pdbm.setOemUnlockEnabled(allowedByDevice);
+    }
+
+    @Override
+    boolean isOemUnlockAllowedByDevice() {
+        final PersistentDataBlockManager pdbm = (PersistentDataBlockManager)
+            mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+        return pdbm.getOemUnlockEnabled();
+    }
+
+    /**
+     * Update state to prevent the bootloader from being able to unlock the device unless the device
+     * has already been unlocked by the bootloader in which case it is too late as it would remain
+     * unlocked.
+     */
+    private void disallowUnlockIfNotUnlocked() {
+        final PersistentDataBlockManager pdbm = (PersistentDataBlockManager)
+            mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+        if (pdbm.getFlashLockState() != PersistentDataBlockManager.FLASH_LOCK_UNLOCKED) {
+            pdbm.setOemUnlockEnabled(false);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/oemlock/VendorLock.java b/services/core/java/com/android/server/oemlock/VendorLock.java
new file mode 100644
index 0000000..1b9de36
--- /dev/null
+++ b/services/core/java/com/android/server/oemlock/VendorLock.java
@@ -0,0 +1,167 @@
+/*
+ * 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.annotation.Nullable;
+import android.content.Context;
+import android.hardware.oemlock.V1_0.IOemLock;
+import android.hardware.oemlock.V1_0.OemLockSecureStatus;
+import android.hardware.oemlock.V1_0.OemLockStatus;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+/**
+ * Uses the OEM lock HAL.
+ */
+class VendorLock extends OemLock {
+    private static final String TAG = "OemLock";
+
+    private Context mContext;
+    private IOemLock mOemLock;
+
+    static IOemLock getOemLockHalService() {
+        try {
+            return IOemLock.getService();
+        } catch (NoSuchElementException e) {
+            Slog.i(TAG, "OemLock HAL not present on device");
+            return null;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    VendorLock(Context context, IOemLock oemLock) {
+        mContext = context;
+        mOemLock = oemLock;
+    }
+
+    @Override
+    void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) {
+        try {
+            switch (mOemLock.setOemUnlockAllowedByCarrier(allowed, toByteArrayList(signature))) {
+                case OemLockSecureStatus.OK:
+                    Slog.i(TAG, "Updated carrier allows OEM lock state to: " + allowed);
+                    return;
+
+                case OemLockSecureStatus.INVALID_SIGNATURE:
+                    throw new SecurityException(
+                            "Invalid signature used in attempt to carrier unlock");
+
+                default:
+                    Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
+                    // Fallthrough
+                case OemLockSecureStatus.FAILED:
+                    throw new RuntimeException("Failed to set carrier OEM unlock state");
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to set carrier state with HAL", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    boolean isOemUnlockAllowedByCarrier() {
+        final Integer[] requestStatus = new Integer[1];
+        final Boolean[] allowedByCarrier = new Boolean[1];
+
+        try {
+            mOemLock.isOemUnlockAllowedByCarrier((status, allowed) -> {
+                requestStatus[0] = status;
+                allowedByCarrier[0] = allowed;
+            });
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to get carrier state from HAL");
+            throw e.rethrowFromSystemServer();
+        }
+
+        switch (requestStatus[0]) {
+            case OemLockStatus.OK:
+                // Success
+                return allowedByCarrier[0];
+
+            default:
+                Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
+                // Fallthrough
+            case OemLockStatus.FAILED:
+                throw new RuntimeException("Failed to get carrier OEM unlock state");
+        }
+    }
+
+    @Override
+    void setOemUnlockAllowedByDevice(boolean allowedByDevice) {
+        try {
+            switch (mOemLock.setOemUnlockAllowedByDevice(allowedByDevice)) {
+                case OemLockSecureStatus.OK:
+                    Slog.i(TAG, "Updated device allows OEM lock state to: " + allowedByDevice);
+                    return;
+
+                default:
+                    Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
+                    // Fallthrough
+                case OemLockSecureStatus.FAILED:
+                    throw new RuntimeException("Failed to set device OEM unlock state");
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to set device state with HAL", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    boolean isOemUnlockAllowedByDevice() {
+        final Integer[] requestStatus = new Integer[1];
+        final Boolean[] allowedByDevice = new Boolean[1];
+
+        try {
+            mOemLock.isOemUnlockAllowedByDevice((status, allowed) -> {
+                requestStatus[0] = status;
+                allowedByDevice[0] = allowed;
+            });
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to get devie state from HAL");
+            throw e.rethrowFromSystemServer();
+        }
+
+        switch (requestStatus[0]) {
+            case OemLockStatus.OK:
+                // Success
+                return allowedByDevice[0];
+
+            default:
+                Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
+                // Fallthrough
+            case OemLockStatus.FAILED:
+                throw new RuntimeException("Failed to get device OEM unlock state");
+        }
+    }
+
+    private ArrayList toByteArrayList(byte[] data) {
+        if (data == null) {
+            return null;
+        }
+        ArrayList<Byte> result = new ArrayList<Byte>(data.length);
+        for (final byte b : data) {
+            result.add(b);
+        }
+        return result;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index c6667a7..a6b05d7 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -31,7 +31,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
-import android.service.persistentdata.PersistentDataBlockManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
@@ -519,22 +518,6 @@
                             android.provider.Settings.Global.SAFE_BOOT_DISALLOWED,
                             newValue ? 1 : 0);
                     break;
-                case UserManager.DISALLOW_FACTORY_RESET:
-                case UserManager.DISALLOW_OEM_UNLOCK:
-                    if (newValue) {
-                        PersistentDataBlockManager manager = (PersistentDataBlockManager) context
-                                .getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
-                        if (manager != null
-                                && manager.getOemUnlockEnabled()
-                                && manager.getFlashLockState()
-                                        != PersistentDataBlockManager.FLASH_LOCK_UNLOCKED) {
-                            // Only disable OEM unlock if the bootloader is locked. If it's already
-                            // unlocked, setting the OEM unlock enabled flag to false has no effect
-                            // (the bootloader would remain unlocked).
-                            manager.setOemUnlockEnabled(false);
-                        }
-                    }
-                    break;
             }
         } finally {
             Binder.restoreCallingIdentity(id);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 38f35c0..71781ac 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -83,6 +83,7 @@
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.notification.NotificationManagerService;
+import com.android.server.oemlock.OemLockService;
 import com.android.server.om.OverlayManagerService;
 import com.android.server.os.DeviceIdentifiersPolicyService;
 import com.android.server.os.SchedulingPolicyService;
@@ -982,12 +983,15 @@
                 }
                 traceEnd();
 
-                if (!SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("")) {
+                final boolean hasPdb = !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("");
+                if (hasPdb) {
                     traceBeginAndSlog("StartPersistentDataBlock");
                     mSystemServiceManager.startService(PersistentDataBlockService.class);
                     traceEnd();
+                }
 
-                    // Implementation depends on persistent data block
+                if (hasPdb || OemLockService.isHalPresent()) {
+                    // Implementation depends on pdb or the OemLock HAL
                     traceBeginAndSlog("StartOemLockService");
                     mSystemServiceManager.startService(OemLockService.class);
                     traceEnd();