Offer the special carrier apps notification only to the owner
The guard designed to only let the owner to explicitly enable/disable matching special
carrier apps was broken as it is always called within the context of the system process
`com.android.phone`, and thus always runs under the system user. On top of it, when the
guard was validated, the app was not disabled and thus could be enabled silently.
Instead, validate that the context in which the match is done comes from the owner.
Any other user will not receive the notification. The special carrier apps will always
be disabled until used in such a context because there cannot be a different user than
the owner created at the first boot.
This is not a complete fix as we would like every user to be presented with the
ability to enable/disable the app when matching.
FPIIM-1459
Change-Id: I3662342f14d170eee4f0cb830797600f0c23f416
diff --git a/src/java/com/android/internal/telephony/CarrierAppUtils.java b/src/java/com/android/internal/telephony/CarrierAppUtils.java
index 8e74c7c..f508daf 100644
--- a/src/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/src/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -23,6 +23,7 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
@@ -172,11 +173,6 @@
Slog.d(TAG, "disableSpecialCarrierAppsUntilMatched");
}
- if (!((UserManager) context.getSystemService(Context.USER_SERVICE)).isSystemUser()) {
- Slog.d(TAG, "Current user is not the owner, special carrier apps matching ignored.");
- return;
- }
-
String[] specialSystemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
com.android.internal.R.array.config_disabledUntilUsedSpecialCarrierApps);
List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
@@ -202,6 +198,7 @@
try {
for (ApplicationInfo ai : candidates) {
String operatorCodesToMatch = null, actionIntentToBroadcast = null;
+ boolean shouldBeMatched = true;
// Only update enabled state for the app on /system. Once it has been updated we
// shouldn't touch it.
@@ -223,24 +220,28 @@
}
}
- // Ignore this candidate if there is no valid operator codes
if (TextUtils.isEmpty(operatorCodesToMatch)) {
+ // There is an error in the configuration
Slog.e(TAG, "No valid operator codes found in the configuration for candidate "
+ ai.packageName);
- continue;
+ // Do not try to match against available operator codes
+ shouldBeMatched = false;
} else if (DEBUG) {
Slog.d(TAG, "Special carrier app candidate (" + ai.packageName
+ ") wants to match against " + operatorCodesToMatch);
}
SpecialCarrierAppInfo appInfo = new SpecialCarrierAppInfo(ai.packageName,
- operatorCodesToMatch, actionIntentToBroadcast);
+ operatorCodesToMatch == null ? "" : operatorCodesToMatch,
+ actionIntentToBroadcast);
- for (int uiccSlot = 0; uiccSlot < simOperatorCodes.length; uiccSlot++) {
- if (appInfo.matchesAgainstOperator(simOperatorCodes[uiccSlot])) {
- appInfo.mUiccSlotId = uiccSlot;
- appInfo.mCarrierName = TelephonyManager.getDefault().getSimOperatorNameForPhone(uiccSlot);
- break;
+ if (shouldBeMatched) {
+ for (int uiccSlot = 0; uiccSlot < simOperatorCodes.length; uiccSlot++) {
+ if (appInfo.matchesAgainstOperator(simOperatorCodes[uiccSlot])) {
+ appInfo.mUiccSlotId = uiccSlot;
+ appInfo.mCarrierName = TelephonyManager.getDefault().getSimOperatorNameForPhone(uiccSlot);
+ break;
+ }
}
}
@@ -254,14 +255,29 @@
boolean isDeviceProvisioned =
Settings.Global.getInt(context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED) == 1;
- /*
- * Defer to the Telephony service to handle the app match.
- */
- context.startService(new Intent()
- .setClassName(context, SPECIAL_CARRIER_APP_INTENT_SERVICE_CLASS)
- .setAction(SPECIAL_CARRIER_APP_ACTION_HANDLE_MATCH)
- .putExtra(SPECIAL_CARRIER_APP_EXTRA_APP_INFO, appInfo)
- .putExtra(SPECIAL_CARRIER_APP_EXTRA_DEVICE_PROVISIONED, isDeviceProvisioned));
+ if (new UserHandle(userId).isOwner()) {
+ if (DEBUG) Slog.d(TAG, "Launching the Telephony service to handle the special carrier app candidate ("
+ + ai.packageName + ") for owner user " + userId);
+ /*
+ * Defer to the Telephony service to handle the app match for the owner.
+ */
+ context.startService(new Intent()
+ .setClassName(context, SPECIAL_CARRIER_APP_INTENT_SERVICE_CLASS)
+ .setAction(SPECIAL_CARRIER_APP_ACTION_HANDLE_MATCH)
+ .putExtra(SPECIAL_CARRIER_APP_EXTRA_APP_INFO, appInfo)
+ .putExtra(SPECIAL_CARRIER_APP_EXTRA_DEVICE_PROVISIONED, isDeviceProvisioned));
+ } else {
+ /*
+ * FIXME: Non-owner users will not have a notification.
+ * The app is left "disabled until used" because there is only one user
+ * created by the first boot - and that is the owner.
+ */
+ Slog.i(TAG, "Update state(" + ai.packageName
+ + "): DISABLED_UNTIL_USED for non-owner user " + userId);
+ packageManager.setApplicationEnabledSetting(ai.packageName,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
+ userId, context.getOpPackageName());
+ }
} else if (!appInfo.hasMatched()
&& ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
Slog.i(TAG, "Update state(" + ai.packageName