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());
- }
- }
-}