Fix telephony service crashing on CryptKeeper mode

This CL reverts the work around in ag/1154152

CryptKeeper mode is the pre-file based encryption locked state, when the
user has selected "Require password to boot" and the device hasn't been
unlocked yet during a reboot. UserManager.isUserUnlocked() will still
return true in this mode, but storage in /data and all content providers
will not be available(including SharedPreference).

With the possibility of no storage being available during locked state,
the method in ag/884393 which requires storing subIds will not work.
Instead, all subIds are sent through voicemail activation again when the
device is unlocked. This will generate a additional activation request
if file based encryption is not enabled, but duplicated requests are
already an issue (b/28730056) and will be resolved in a future CL.

Change-Id: I75753f67b8598d64c33c83cb6598497664ba4acd
Fixes: 29358683
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a867260..4a95259 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -678,7 +678,7 @@
             </intent-filter>
         </receiver>
         <receiver
-            android:name="com.android.phone.vvm.omtp.OmtpBootCompletedReceiver"
+            android:name="com.android.phone.vvm.omtp.VvmBootCompletedReceiver"
             android:exported="true"
             android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
             <intent-filter>
diff --git a/src/com/android/phone/vvm/omtp/OmtpBootCompletedReceiver.java b/src/com/android/phone/vvm/omtp/OmtpBootCompletedReceiver.java
deleted file mode 100644
index a2b85f7..0000000
--- a/src/com/android/phone/vvm/omtp/OmtpBootCompletedReceiver.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2016 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.phone.vvm.omtp;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Set;
-
-/**
- * Stores subscription ID of SIMs while the device is locked to process them after the device is
- * unlocked. This class is only intended to be used within {@link SimChangeReceiver}. subId is used
- * for Visual voicemail activation/deactivation, which need to be done when the device is unlocked.
- * But the enumeration of subIds happen on boot, when the device could be locked. This class is used
- * to defer all activation/deactivation until the device is unlocked.
- *
- * The subIds are stored in device encrypted {@link SharedPreferences} (readable/writable even
- * locked). after the device is unlocked the list is read and deleted.
- */
-public class OmtpBootCompletedReceiver extends BroadcastReceiver {
-
-    private static final String TAG = "OmtpBootCompletedRcvr";
-
-    private static final String DEFERRED_SUBID_LIST_KEY = "deferred_sub_id_key";
-
-    @VisibleForTesting
-    interface SubIdProcessor{
-        void process(Context context,int subId);
-    }
-
-    private SubIdProcessor mSubIdProcessor = new SubIdProcessor() {
-        @Override
-        public void process(Context context, int subId) {
-            SimChangeReceiver.processSubId(context,subId);
-        }
-    };
-
-    /**
-     * Write the subId to the the list.
-     */
-    public static void addDeferredSubId(Context context, int subId) {
-        SharedPreferences sharedPreferences = getSubIdSharedPreference(context);
-        Set<String> subIds =
-                new ArraySet<>(sharedPreferences.getStringSet(DEFERRED_SUBID_LIST_KEY, null));
-        subIds.add(String.valueOf(subId));
-        sharedPreferences.edit().putStringSet(DEFERRED_SUBID_LIST_KEY, subIds).apply();
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        // Listens to android.intent.action.BOOT_COMPLETED
-        if(!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
-            return;
-        }
-
-        Log.v(TAG, "processing deferred subId list");
-        Set<Integer> subIds = readAndDeleteSubIds(context);
-        for (Integer subId : subIds) {
-            Log.v(TAG, "processing subId " + subId);
-            mSubIdProcessor.process(context, subId);
-        }
-    }
-
-    /**
-     * Read all subId from the list to a unique integer set, and delete the preference.
-     */
-    private static Set<Integer> readAndDeleteSubIds(Context context) {
-        SharedPreferences sharedPreferences = getSubIdSharedPreference(context);
-        Set<String> subIdStrings = sharedPreferences.getStringSet(DEFERRED_SUBID_LIST_KEY, null);
-        Set<Integer> subIds = new ArraySet<>();
-        if(subIdStrings == null) {
-            return subIds;
-        }
-        for(String string : subIdStrings){
-            subIds.add(Integer.valueOf(string));
-        }
-        getSubIdSharedPreference(context).edit().remove(DEFERRED_SUBID_LIST_KEY).apply();
-        return subIds;
-    }
-
-    @VisibleForTesting
-    void setSubIdProcessorForTest(SubIdProcessor processor){
-        mSubIdProcessor = processor;
-    }
-
-    private static SharedPreferences getSubIdSharedPreference(Context context) {
-        return PreferenceManager
-                .getDefaultSharedPreferences(context.createDeviceProtectedStorageContext());
-    }
-}
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
index 677e8b2..323b423 100644
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
@@ -18,6 +18,9 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.telecom.PhoneAccountHandle;
@@ -75,26 +78,12 @@
                     return;
                 }
                 Log.d(TAG, "Carrier config changed");
-                if (!UserManager.get(context).isUserUnlocked()) {
-                    Log.d(TAG, "User locked, activation request delayed until unlock");
-                    OmtpBootCompletedReceiver.addDeferredSubId(context, subId);
+                if (UserManager.get(context).isUserUnlocked() && !isCryptKeeperMode()) {
+                    processSubId(context, subId);
                 } else {
-                    try {
-                        processSubId(context, subId);
-                    } catch (IllegalArgumentException e) {
-                        // b/29358683 for some unknown reason UserManager.isUserUnlocked() could
-                        // return true even if the device is not unlocked, which will cause a
-                        // IllegalArgumentException when trying to write voicemail status.
-                        // Catch it as a workaround while investigating.
-                        Log.e(TAG, e.toString());
-                        Log.e(TAG, "UserManager.isUserUnlocked: " + UserManager.get(context)
-                            .isUserUnlocked());
-                        PhoneAccountHandle phoneAccount = PhoneAccountHandleConverter
-                            .fromSubId(subId);
-                        OmtpVvmSourceManager.getInstance(context)
-                            .removePhoneStateListener(phoneAccount);
-                        OmtpBootCompletedReceiver.addDeferredSubId(context, subId);
-                    }
+                    Log.d(TAG, "User locked, activation request delayed until unlock");
+                    // After the device is unlocked, VvmBootCompletedReceiver will iterate through
+                    // all call capable subIds, nothing need to be done here.
                 }
                 break;
         }
@@ -131,4 +120,19 @@
                     "visual voicemail not supported for carrier " + mccMnc + " on subId " + subId);
         }
     }
+
+    /**
+     * CryptKeeper mode is the pre-file based encryption locked state, when the user has selected
+     * "Require password to boot" and the device hasn't been unlocked yet during a reboot. {@link
+     * UserManager#isUserUnlocked()} will still return true in this mode, but storage in /data and
+     * all content providers will not be available(including SharedPreference).
+     */
+    private static boolean isCryptKeeperMode() {
+        try {
+            return IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
+                    isOnlyCoreApps();
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java b/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java
new file mode 100644
index 0000000..b60c7b6
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.phone.vvm.omtp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.util.Log;
+
+import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
+
+/**
+ * Upon boot iterate through all callable phone account to activate visual voicemail. This happens
+ * after the device has been unlocked. {@link android.telephony.CarrierConfigManager#
+ * ACTION_CARRIER_CONFIG_CHANGED} can also trigger activation upon boot but it can happen before the
+ * device is unlocked and visual voicemail will not be activated.
+ *
+ * <p>TODO: An additional duplicated activation request will be sent as a result of this receiver,
+ * but similar issues is already covered in b/28730056 and a scheduling system should be used to
+ * resolve this.
+ */
+public class VvmBootCompletedReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "VvmBootCompletedRcvr";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // Listens to android.intent.action.BOOT_COMPLETED
+        if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
+            return;
+        }
+
+        Log.v(TAG, "processing subId list");
+        for (PhoneAccountHandle handle : TelecomManager.from(context)
+                .getCallCapablePhoneAccounts()) {
+            int subId = PhoneAccountHandleConverter.toSubId(handle);
+            Log.v(TAG, "processing subId " + subId);
+            SimChangeReceiver.processSubId(context, subId);
+        }
+    }
+}
diff --git a/tests/src/com/android/phone/vvm/omtp/OmtpBootCompletedReceiverTests.java b/tests/src/com/android/phone/vvm/omtp/OmtpBootCompletedReceiverTests.java
deleted file mode 100644
index 1924d9f..0000000
--- a/tests/src/com/android/phone/vvm/omtp/OmtpBootCompletedReceiverTests.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2016 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.phone.vvm.omtp;
-
-import android.content.Context;
-import android.content.Intent;
-import android.preference.PreferenceManager;
-import android.test.AndroidTestCase;
-import android.util.ArraySet;
-
-import com.android.phone.vvm.omtp.OmtpBootCompletedReceiver.SubIdProcessor;
-
-import java.util.Set;
-
-public class OmtpBootCompletedReceiverTests extends AndroidTestCase {
-    OmtpBootCompletedReceiver mReceiver = new OmtpBootCompletedReceiver();
-    @Override
-    public void setUp() {
-    }
-
-    @Override
-    public void tearDown() {
-        PreferenceManager
-                .getDefaultSharedPreferences(getContext().createDeviceProtectedStorageContext())
-                .edit().clear().apply();
-    }
-
-    public void testReadWriteList() {
-        readWriteList(new int[] {1});
-    }
-
-    public void testReadWriteList_Multiple() {
-        readWriteList(new int[] {1, 2});
-    }
-
-    public void testReadWriteList_Duplicate() {
-        readWriteList(new int[] {1, 1});
-    }
-
-    private void readWriteList(int[] values) {
-        for (int value : values) {
-            OmtpBootCompletedReceiver.addDeferredSubId(getContext(), value);
-        }
-        TestSubIdProcessor processor = new TestSubIdProcessor(values);
-        mReceiver.setSubIdProcessorForTest(processor);
-        Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
-        mReceiver.onReceive(getContext(), intent);
-        processor.assertMatch();
-        // after onReceive() is called the list should be empty
-        TestSubIdProcessor emptyProcessor = new TestSubIdProcessor(new int[] {});
-        mReceiver.setSubIdProcessorForTest(processor);
-        mReceiver.onReceive(getContext(), intent);
-        processor.assertMatch();
-    }
-
-    private static class TestSubIdProcessor implements SubIdProcessor {
-        private final Set<Integer> mExpectedSubIds;
-
-        public TestSubIdProcessor(int[] expectedSubIds) {
-            mExpectedSubIds = new ArraySet<>();
-            for(int subId : expectedSubIds){
-                mExpectedSubIds.add(subId);
-            }
-        }
-
-        @Override
-        public void process(Context context, int subId){
-            assertTrue(mExpectedSubIds.contains(subId));
-            mExpectedSubIds.remove(subId);
-        }
-
-        public void assertMatch(){
-            assertTrue(mExpectedSubIds.isEmpty());
-        }
-    }
-}