Merge changes Icf10d577,Ia9d3cae7

* changes:
  Factor out a class to store the rebootEscrow key
  Add namespace in DeviceConfig to support ota teams's features
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 244df9b..de8e180 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -7886,6 +7886,7 @@
     field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
     field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+    field public static final String NAMESPACE_OTA = "ota";
     field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
     field public static final String NAMESPACE_PERMISSIONS = "permissions";
     field public static final String NAMESPACE_PRIVACY = "privacy";
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 4d67d46..e7e2c61 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -403,6 +403,14 @@
     public static final String NAMESPACE_PERMISSIONS = "permissions";
 
     /**
+     * Namespace for ota related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_OTA = "ota";
+
+    /**
      * Namespace for all widget related features.
      *
      * @hide
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 5787f7c4..8d5f553 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -15,20 +15,15 @@
  */
 
 package com.android.server.locksettings;
-
 import static android.os.UserHandle.USER_SYSTEM;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.pm.UserInfo;
-import android.hardware.rebootescrow.IRebootEscrow;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.util.Slog;
 
@@ -44,7 +39,6 @@
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
-import java.util.NoSuchElementException;
 
 class RebootEscrowManager {
     private static final String TAG = "RebootEscrowManager";
@@ -116,8 +110,24 @@
     static class Injector {
         protected Context mContext;
 
+        private final RebootEscrowProviderInterface mRebootEscrowProvider;
+
         Injector(Context context) {
             mContext = context;
+            RebootEscrowProviderInterface rebootEscrowProvider = null;
+            // TODO(xunchang) add implementation for server based ror.
+            if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
+                    "server_based_ror_enabled", false)) {
+                Slog.e(TAG, "Server based ror isn't implemented yet.");
+            } else {
+                rebootEscrowProvider = new RebootEscrowProviderHalImpl();
+            }
+
+            if (rebootEscrowProvider != null && rebootEscrowProvider.hasRebootEscrowSupport()) {
+                mRebootEscrowProvider = rebootEscrowProvider;
+            } else {
+                mRebootEscrowProvider = null;
+            }
         }
 
         public Context getContext() {
@@ -128,15 +138,8 @@
             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         }
 
-        @Nullable
-        public IRebootEscrow getRebootEscrow() {
-            try {
-                return IRebootEscrow.Stub.asInterface(ServiceManager.getService(
-                        "android.hardware.rebootescrow.IRebootEscrow/default"));
-            } catch (NoSuchElementException e) {
-                Slog.i(TAG, "Device doesn't implement RebootEscrow HAL");
-            }
-            return null;
+        public RebootEscrowProviderInterface getRebootEscrowProvider() {
+            return mRebootEscrowProvider;
         }
 
         public int getBootCount() {
@@ -210,45 +213,18 @@
     }
 
     private RebootEscrowKey getAndClearRebootEscrowKey() {
-        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
-        if (rebootEscrow == null) {
-            Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrow HAL is unavailable");
+        RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
+        if (rebootEscrowProvider == null) {
+            Slog.w(TAG,
+                    "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
             return null;
         }
 
-        try {
-            byte[] escrowKeyBytes = rebootEscrow.retrieveKey();
-            if (escrowKeyBytes == null) {
-                Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key");
-                return null;
-            } else if (escrowKeyBytes.length != 32) {
-                Slog.e(TAG, "IRebootEscrow returned key of incorrect size "
-                        + escrowKeyBytes.length);
-                return null;
-            }
-
-            // Make sure we didn't get the null key.
-            int zero = 0;
-            for (int i = 0; i < escrowKeyBytes.length; i++) {
-                zero |= escrowKeyBytes[i];
-            }
-            if (zero == 0) {
-                Slog.w(TAG, "IRebootEscrow returned an all-zeroes key");
-                return null;
-            }
-
-            // Overwrite the existing key with the null key
-            rebootEscrow.storeKey(new byte[32]);
-
+        RebootEscrowKey key = rebootEscrowProvider.getAndClearRebootEscrowKey(null);
+        if (key != null) {
             mEventLog.addEntry(RebootEscrowEvent.RETRIEVED_STORED_KEK);
-            return RebootEscrowKey.fromKeyBytes(escrowKeyBytes);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Could not retrieve escrow data");
-            return null;
-        } catch (ServiceSpecificException e) {
-            Slog.w(TAG, "Got service-specific exception: " + e.errorCode);
-            return null;
         }
+        return key;
     }
 
     private boolean restoreRebootEscrowForUser(@UserIdInt int userId, RebootEscrowKey key) {
@@ -279,9 +255,9 @@
             return;
         }
 
-        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
-        if (rebootEscrow == null) {
-            Slog.w(TAG, "Reboot escrow requested, but RebootEscrow HAL is unavailable");
+        if (mInjector.getRebootEscrowProvider() == null) {
+            Slog.w(TAG,
+                    "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
             return;
         }
 
@@ -293,6 +269,7 @@
 
         final RebootEscrowData escrowData;
         try {
+            // TODO(xunchang) further wrap the escrowData with a key from keystore.
             escrowData = RebootEscrowData.fromSyntheticPassword(escrowKey, spVersion,
                     syntheticPassword);
         } catch (IOException e) {
@@ -330,18 +307,16 @@
         mRebootEscrowWanted = false;
         setRebootEscrowReady(false);
 
-        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
-        if (rebootEscrow == null) {
+
+        RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
+        if (rebootEscrowProvider == null) {
+            Slog.w(TAG,
+                    "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
             return;
         }
 
         mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
-
-        try {
-            rebootEscrow.storeKey(new byte[32]);
-        } catch (RemoteException | ServiceSpecificException e) {
-            Slog.w(TAG, "Could not call RebootEscrow HAL to shred key");
-        }
+        rebootEscrowProvider.clearRebootEscrowKey();
 
         List<UserInfo> users = mUserManager.getUsers();
         for (UserInfo user : users) {
@@ -356,9 +331,10 @@
             return false;
         }
 
-        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
-        if (rebootEscrow == null) {
-            Slog.w(TAG, "Escrow marked as ready, but RebootEscrow HAL is unavailable");
+        RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
+        if (rebootEscrowProvider == null) {
+            Slog.w(TAG,
+                    "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
             return false;
         }
 
@@ -372,15 +348,7 @@
             return false;
         }
 
-        boolean armedRebootEscrow = false;
-        try {
-            rebootEscrow.storeKey(escrowKey.getKeyBytes());
-            armedRebootEscrow = true;
-            Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL");
-        } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e);
-        }
-
+        boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, null);
         if (armedRebootEscrow) {
             mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
             mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
@@ -397,7 +365,7 @@
     }
 
     boolean prepareRebootEscrow() {
-        if (mInjector.getRebootEscrow() == null) {
+        if (mInjector.getRebootEscrowProvider() == null) {
             return false;
         }
 
@@ -408,7 +376,7 @@
     }
 
     boolean clearRebootEscrow() {
-        if (mInjector.getRebootEscrow() == null) {
+        if (mInjector.getRebootEscrowProvider() == null) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
new file mode 100644
index 0000000..6c1040b
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2020 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.locksettings;
+
+import android.annotation.Nullable;
+import android.hardware.rebootescrow.IRebootEscrow;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+
+import javax.crypto.SecretKey;
+
+/**
+ * An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL.
+ */
+class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface {
+    private static final String TAG = "RebootEscrowProvider";
+
+    private final Injector mInjector;
+
+    static class Injector {
+        @Nullable
+        public IRebootEscrow getRebootEscrow() {
+            try {
+                return IRebootEscrow.Stub.asInterface(ServiceManager.getService(
+                        "android.hardware.rebootescrow.IRebootEscrow/default"));
+            } catch (NoSuchElementException e) {
+                Slog.i(TAG, "Device doesn't implement RebootEscrow HAL");
+            }
+            return null;
+        }
+    }
+
+    RebootEscrowProviderHalImpl() {
+        mInjector = new Injector();
+    }
+
+    @VisibleForTesting
+    RebootEscrowProviderHalImpl(Injector injector) {
+        mInjector = injector;
+    }
+
+    @Override
+    public boolean hasRebootEscrowSupport() {
+        return mInjector.getRebootEscrow() != null;
+    }
+
+    @Override
+    public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) {
+        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
+        if (rebootEscrow == null) {
+            Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrow HAL is unavailable");
+            return null;
+        }
+
+        try {
+            byte[] escrowKeyBytes = rebootEscrow.retrieveKey();
+            if (escrowKeyBytes == null) {
+                Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key");
+                return null;
+            } else if (escrowKeyBytes.length != 32) {
+                Slog.e(TAG, "IRebootEscrow returned key of incorrect size "
+                        + escrowKeyBytes.length);
+                return null;
+            }
+
+            // Make sure we didn't get the null key.
+            int zero = 0;
+            for (int i = 0; i < escrowKeyBytes.length; i++) {
+                zero |= escrowKeyBytes[i];
+            }
+            if (zero == 0) {
+                Slog.w(TAG, "IRebootEscrow returned an all-zeroes key");
+                return null;
+            }
+
+            // Overwrite the existing key with the null key
+            rebootEscrow.storeKey(new byte[32]);
+
+            return RebootEscrowKey.fromKeyBytes(escrowKeyBytes);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Could not retrieve escrow data");
+            return null;
+        } catch (ServiceSpecificException e) {
+            Slog.w(TAG, "Got service-specific exception: " + e.errorCode);
+            return null;
+        }
+    }
+
+    @Override
+    public void clearRebootEscrowKey() {
+        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
+        if (rebootEscrow == null) {
+            return;
+        }
+
+        try {
+            rebootEscrow.storeKey(new byte[32]);
+        } catch (RemoteException | ServiceSpecificException e) {
+            Slog.w(TAG, "Could not call RebootEscrow HAL to shred key");
+        }
+
+    }
+
+    @Override
+    public boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey) {
+        IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
+        if (rebootEscrow == null) {
+            Slog.w(TAG, "Escrow marked as ready, but RebootEscrow HAL is unavailable");
+            return false;
+        }
+
+        try {
+            // The HAL interface only accept 32 bytes data. And the encrypted bytes for the escrow
+            // key may exceed that limit. So we just store the raw key bytes here.
+            rebootEscrow.storeKey(escrowKey.getKeyBytes());
+            Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL");
+            return true;
+        } catch (RemoteException | ServiceSpecificException e) {
+            Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e);
+        }
+        return false;
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
new file mode 100644
index 0000000..857ad5f
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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.locksettings;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Provides APIs for {@link RebootEscrowManager} to access and manage the reboot escrow key.
+ * Implementations need to find a way to persist the key across a reboot, and securely discards the
+ * persisted copy.
+ *
+ * @hide
+ */
+public interface RebootEscrowProviderInterface {
+    /**
+     * Returns true if the secure store/discard of reboot escrow key is supported.
+     */
+    boolean hasRebootEscrowSupport();
+
+    /**
+     * Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted,
+     * use the input key to decrypt the RebootEscrowKey. Returns null on failure.
+     */
+    RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey);
+
+    /**
+     * Clears the stored RebootEscrowKey.
+     */
+    void clearRebootEscrowKey();
+
+    /**
+     * Saves the given RebootEscrowKey, optionally encrypt the storage with the encryptionKey.
+     */
+    boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey);
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index c4d1211..98d6452 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -95,13 +95,24 @@
 
     static class MockInjector extends RebootEscrowManager.Injector {
         private final IRebootEscrow mRebootEscrow;
+        private final RebootEscrowProviderInterface mRebootEscrowProvider;
         private final UserManager mUserManager;
         private final MockableRebootEscrowInjected mInjected;
 
-        MockInjector(Context context, UserManager userManager, IRebootEscrow rebootEscrow,
+        MockInjector(Context context, UserManager userManager,
+                IRebootEscrow rebootEscrow,
                 MockableRebootEscrowInjected injected) {
             super(context);
             mRebootEscrow = rebootEscrow;
+
+            RebootEscrowProviderHalImpl.Injector halInjector =
+                    new RebootEscrowProviderHalImpl.Injector() {
+                        @Override
+                        public IRebootEscrow getRebootEscrow() {
+                            return mRebootEscrow;
+                        }
+                    };
+            mRebootEscrowProvider = new RebootEscrowProviderHalImpl(halInjector);
             mUserManager = userManager;
             mInjected = injected;
         }
@@ -112,8 +123,8 @@
         }
 
         @Override
-        public IRebootEscrow getRebootEscrow() {
-            return mRebootEscrow;
+        public RebootEscrowProviderInterface getRebootEscrowProvider() {
+            return mRebootEscrowProvider;
         }
 
         @Override