KeyStore: add "migrate" command

To support the WiFi service, we need to support migration from the
system UID to the wifi UID. This adds a command to achieve the
migration.

Bug: 8122243
Change-Id: I65f7a91504c1d2a2aac22b9c3051adffd28d66c1
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index af4cdfa..2ae3c64 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -405,6 +405,25 @@
                 }
                 return _result;
             }
+
+            @Override
+            public int migrate(String name, int targetUid) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(name);
+                    _data.writeInt(targetUid);
+                    mRemote.transact(Stub.TRANSACTION_migrate, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
         }
 
         private static final String DESCRIPTOR = "android.security.keystore";
@@ -429,6 +448,7 @@
         static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17;
         static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18;
         static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19;
+        static final int TRANSACTION_migrate = IBinder.FIRST_CALL_TRANSACTION + 20;
 
         /**
          * Cast an IBinder object into an IKeystoreService interface, generating
@@ -513,4 +533,6 @@
     public int ungrant(String name, int granteeUid) throws RemoteException;
 
     public long getmtime(String name) throws RemoteException;
+
+    public int migrate(String name, int targetUid) throws RemoteException;
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 9000668..4dc0beb 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -287,6 +287,15 @@
         }
     }
 
+    public boolean migrate(String key, int uid) {
+        try {
+            return mBinder.migrate(key, uid) == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
     public int getLastError() {
         return mError;
     }
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 6ce3ed3..8f8ee92 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -553,6 +553,38 @@
                 mKeyStore.ungrant(TEST_KEYNAME, 0));
     }
 
+    public void testMigrate_grantedUid_Wifi_Success() throws Exception {
+        assertTrue(mKeyStore.password(TEST_PASSWD));
+
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
+
+        assertTrue(mKeyStore.generate(TEST_KEYNAME));
+
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+
+        assertTrue(mKeyStore.migrate(TEST_KEYNAME, Process.WIFI_UID));
+
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+    }
+
+    public void testMigrate_ungrantedUid_Bluetooth_Failure() throws Exception {
+        assertTrue(mKeyStore.password(TEST_PASSWD));
+
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
+
+        assertTrue(mKeyStore.generate(TEST_KEYNAME));
+
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+        assertFalse(mKeyStore.migrate(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+    }
+
     /**
      * The amount of time to allow before and after expected time for variance
      * in timing tests.