Merge "Mirgate default SMS app handling to RoleManager"

This commit is contained in:
Eugene Susla
2019-01-11 21:23:34 +00:00
committed by Android (Google) Code Review
12 changed files with 349 additions and 85 deletions

View File

@@ -50,4 +50,6 @@ interface IRoleManager {
boolean removeRoleHolderFromController(in String roleName, in String packageName);
List<String> getHeldRolesFromController(in String packageName);
String getDefaultSmsPackage(int userId);
}

View File

@@ -19,6 +19,7 @@ package android.app.role;
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -592,7 +593,6 @@ public final class RoleManager {
}
}
/**
* Returns the list of all roles that the given package is currently holding
*
@@ -613,6 +613,22 @@ public final class RoleManager {
}
}
/**
* Allows getting the role holder for {@link #ROLE_SMS} without
* {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
* {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
*
* @hide
*/
@Nullable
public String getDefaultSmsPackage(@UserIdInt int userId) {
try {
return mService.getDefaultSmsPackage(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private static class RoleManagerCallbackDelegate extends IRoleManagerCallback.Stub {
@NonNull

View File

@@ -29,8 +29,11 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import android.annotation.UnsupportedAppUsage;
import android.os.BaseBundle;
import android.os.Debug;
import android.os.PersistableBundle;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -43,6 +46,9 @@ import java.util.Objects;
* @hide
*/
public class PackageUserState {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "PackageUserState";
public long ceDataInode;
public boolean installed;
public boolean stopped;
@@ -132,12 +138,12 @@ public class PackageUserState {
final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
if (!isAvailable(flags)
&& !(isSystemApp && matchUninstalled)) return false;
if (!isEnabled(componentInfo, flags)) return false;
&& !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags);
if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags);
if ((flags & MATCH_SYSTEM_ONLY) != 0) {
if (!isSystemApp) {
return false;
return reportIfDebug(false, flags);
}
}
@@ -145,7 +151,16 @@ public class PackageUserState {
&& !componentInfo.directBootAware;
final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
&& componentInfo.directBootAware;
return matchesUnaware || matchesAware;
return reportIfDebug(matchesUnaware || matchesAware, flags);
}
private boolean reportIfDebug(boolean result, int flags) {
if (DEBUG && !result) {
Slog.i(LOG_TAG, "No match!; flags: "
+ DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
+ Debug.getCaller());
}
return result;
}
/**

View File

@@ -18,6 +18,7 @@ package android.util;
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -250,7 +251,7 @@ public class DebugUtils {
if (value == 0 && flagsWasZero) {
return constNameWithoutPrefix(prefix, field);
}
if ((flags & value) != 0) {
if ((flags & value) == value) {
flags &= ~value;
res.append(constNameWithoutPrefix(prefix, field)).append('|');
}

View File

@@ -330,4 +330,18 @@ public class CollectionUtils {
public static @NonNull <T> List<T> defeatNullable(@Nullable List<T> val) {
return (val != null) ? val : Collections.emptyList();
}
/**
* @return the first element if not empty/null, null otherwise
*/
public static @Nullable <T> T firstOrNull(@Nullable List<T> cur) {
return isEmpty(cur) ? null : cur.get(0);
}
/**
* @return list of single given element if it's not null, empty list otherwise
*/
public static @NonNull <T> List<T> singletonOrEmpty(@Nullable T item) {
return item == null ? Collections.emptyList() : Collections.singletonList(item);
}
}

View File

@@ -16,6 +16,22 @@
package com.android.server;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.FastImmutableArraySet;
import android.util.Log;
import android.util.LogPrinter;
import android.util.MutableInt;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.FastPrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -25,23 +41,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
import android.net.Uri;
import android.util.FastImmutableArraySet;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.MutableInt;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.LogPrinter;
import android.util.Printer;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.FastPrintWriter;
/**
* {@hide}
*/
@@ -788,6 +787,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
+ filter.hasCategory(Intent.CATEGORY_DEFAULT));
if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
final R oneResult = newResult(filter, match, userId);
if (debug) Slog.v(TAG, " Created result: " + oneResult);
if (oneResult != null) {
dest.add(oneResult);
if (debug) {

View File

@@ -42,6 +42,7 @@ import android.content.pm.ServiceInfo;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
import android.util.LogPrinter;
import android.util.Pair;
@@ -60,6 +61,7 @@ import java.util.Set;
/** Resolves all Android component types [activities, services, providers and receivers]. */
public class ComponentResolver {
private static final boolean DEBUG = false;
private static final String TAG = "PackageManager";
private static final boolean DEBUG_FILTERS = false;
private static final boolean DEBUG_SHOW_INFO = false;
@@ -1198,22 +1200,48 @@ public class ComponentResolver {
return packageName.equals(info.activity.owner.packageName);
}
private void log(String reason, ActivityIntentInfo info, int match,
int userId) {
Slog.w(TAG, reason
+ "; match: "
+ DebugUtils.flagsToString(IntentFilter.class, "MATCH_", match)
+ "; userId: " + userId
+ "; intent info: " + info);
}
@Override
protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
int match, int userId) {
if (!sUserManager.exists(userId)) return null;
if (!sUserManager.exists(userId)) {
if (DEBUG) {
log("User doesn't exist", info, match, userId);
}
return null;
}
if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) {
if (DEBUG) {
log("!PackageManagerInternal.isEnabledAndMatches; mFlags="
+ DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags),
info, match, userId);
}
return null;
}
final PackageParser.Activity activity = info.activity;
PackageSetting ps = (PackageSetting) activity.owner.mExtras;
if (ps == null) {
if (DEBUG) {
log("info.activity.owner.mExtras == null", info, match, userId);
}
return null;
}
final PackageUserState userState = ps.readUserState(userId);
ActivityInfo ai =
PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
if (ai == null) {
if (DEBUG) {
log("Failed to create ActivityInfo based on " + info.activity, info, match,
userId);
}
return null;
}
final boolean matchExplicitlyVisibleOnly =
@@ -1227,15 +1255,31 @@ public class ComponentResolver {
final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
// throw out filters that aren't visible to ephemeral apps
if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) {
if (DEBUG) {
log("Filter(s) not visible to ephemeral apps"
+ "; matchVisibleToInstantApp=" + matchVisibleToInstantApp
+ "; matchInstantApp=" + matchInstantApp
+ "; info.isVisibleToInstantApp()=" + info.isVisibleToInstantApp()
+ "; matchExplicitlyVisibleOnly=" + matchExplicitlyVisibleOnly
+ "; info.isExplicitlyVisibleToInstantApp()="
+ info.isExplicitlyVisibleToInstantApp(),
info, match, userId);
}
return null;
}
// throw out instant app filters if we're not explicitly requesting them
if (!matchInstantApp && userState.instantApp) {
if (DEBUG) {
log("Instant app filter is not explicitly requested", info, match, userId);
}
return null;
}
// throw out instant app filters if updates are available; will trigger
// instant app resolution
if (userState.instantApp && ps.isUpdateAvailable()) {
if (DEBUG) {
log("Instant app update is available", info, match, userId);
}
return null;
}
final ResolveInfo res = new ResolveInfo();

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2018 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.policy.role;
import android.annotation.NonNull;
import android.app.role.RoleManager;
import android.content.Context;
import android.os.Debug;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.CollectionUtils;
import com.android.server.role.RoleManagerService;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Logic to retrieve the various legacy(pre-Q) equivalents of role holders.
*
* Unlike {@link RoleManagerService} this is meant to be pretty high-level to allow for depending
* on all kinds of various systems that are historically involved in legacy role resolution,
* e.g. {@link SmsApplication}
*
* @see RoleManagerService#migrateRoleIfNecessary
*/
public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHoldersResolver {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "LegacyRoleResolutionPol";
@NonNull
private final Context mContext;
public LegacyRoleResolutionPolicy(Context context) {
mContext = context;
}
@Override
public List<String> getRoleHolders(String roleName, int userId) {
switch (roleName) {
case RoleManager.ROLE_SMS: {
// Moved over from SmsApplication#getApplication
String result = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
if (result == null) {
Collection<SmsApplication.SmsApplicationData> applications =
SmsApplication.getApplicationCollectionAsUser(mContext, userId);
SmsApplication.SmsApplicationData applicationData;
String defaultPackage = mContext.getResources()
.getString(com.android.internal.R.string.default_sms_application);
applicationData =
SmsApplication.getApplicationForPackage(applications, defaultPackage);
if (applicationData == null) {
// Are there any applications?
if (applications.size() != 0) {
applicationData =
(SmsApplication.SmsApplicationData) applications.toArray()[0];
}
}
if (DEBUG) {
Log.i(LOG_TAG, "Found default sms app: " + applicationData
+ " among: " + applications + " from " + Debug.getCallers(4));
}
SmsApplication.SmsApplicationData app = applicationData;
result = app == null ? null : app.mPackageName;
}
return CollectionUtils.singletonOrEmpty(result);
}
default: {
Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName);
return Collections.emptyList();
}
}
}
}

View File

@@ -35,6 +35,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Binder;
import android.os.Handler;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -92,6 +93,15 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@NonNull
private final Object mLock = new Object();
@NonNull
private final RoleHoldersResolver mLegacyRoleResolver;
/** @see #getRoleHolders(String, int) */
public interface RoleHoldersResolver {
/** @return a list of packages that hold a given role for a given user */
List<String> getRoleHolders(String roleName, int userId);
}
/**
* Maps user id to its state.
*/
@@ -118,9 +128,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@NonNull
private final Handler mListenerHandler = FgThread.getHandler();
public RoleManagerService(@NonNull Context context) {
public RoleManagerService(@NonNull Context context,
@NonNull RoleHoldersResolver legacyRoleResolver) {
super(context);
mLegacyRoleResolver = legacyRoleResolver;
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
@@ -175,10 +188,17 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
RoleUserState userState;
userState = getOrCreateUserState(userId);
String packagesHash = computeComponentStateHash(userId);
String oldPackagesHash = userState.getPackagesHash();
boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
if (needGrant) {
//TODO gradually add more role migrations statements here for remaining roles
// Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
// for a given role before adding a migration statement for it here
migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
// Some vital packages state has changed since last role grant
// Run grants again
Slog.i(LOG_TAG, "Granting default permissions...");
@@ -205,6 +225,20 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
}
private void migrateRoleIfNecessary(String role, @UserIdInt int userId) {
// Any role for which we have a record are already migrated
RoleUserState userState = getOrCreateUserState(userId);
if (!userState.isRoleAvailable(role)) {
userState.addRoleName(role);
List<String> roleHolders = mLegacyRoleResolver.getRoleHolders(role, userId);
Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders);
int size = roleHolders.size();
for (int i = 0; i < size; i++) {
userState.addRoleHolder(role, roleHolders.get(i));
}
}
}
@Nullable
private static String computeComponentStateHash(@UserIdInt int userId) {
PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
@@ -372,6 +406,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@Nullable
private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName,
@UserIdInt int userId) {
migrateRoleIfNecessary(roleName, userId);
RoleUserState userState = getOrCreateUserState(userId);
return userState.getRoleHolders(roleName);
}
@@ -529,6 +564,17 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
resultReceiver);
}
@Override
public String getDefaultSmsPackage(int userId) {
long identity = Binder.clearCallingIdentity();
try {
return CollectionUtils.firstOrNull(
getRoleHoldersAsUser(RoleManager.ROLE_SMS, userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {

View File

@@ -204,6 +204,28 @@ public class RoleUserState {
}
}
/**
* Adds the given role, effectively marking it as {@link #isRoleAvailable available}
*
* @param roleName the name of the role
*
* @return whether any changes were made
*/
public boolean addRoleName(@NonNull String roleName) {
synchronized (mLock) {
throwIfDestroyedLocked();
if (!mRoles.containsKey(roleName)) {
mRoles.put(roleName, new ArraySet<>());
Slog.i(LOG_TAG, "Added new role: " + roleName);
scheduleWriteFileLocked();
return true;
} else {
return false;
}
}
}
/**
* Set the names of all available roles.
*
@@ -231,13 +253,7 @@ public class RoleUserState {
int roleNamesSize = roleNames.size();
for (int i = 0; i < roleNamesSize; i++) {
String roleName = roleNames.get(i);
if (!mRoles.containsKey(roleName)) {
mRoles.put(roleName, new ArraySet<>());
Slog.i(LOG_TAG, "Added new role: " + roleName);
changed = true;
}
changed |= addRoleName(roleNames.get(i));
}
if (changed) {

View File

@@ -120,6 +120,7 @@ import com.android.server.pm.PackageManagerService;
import com.android.server.pm.ShortcutService;
import com.android.server.pm.UserManagerService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.policy.role.LegacyRoleResolutionPolicy;
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.power.ThermalManagerService;
@@ -1991,7 +1992,8 @@ public final class SystemServer {
// Grants default permissions and defines roles
traceBeginAndSlog("StartRoleManagerService");
mSystemServiceManager.startService(RoleManagerService.class);
mSystemServiceManager.startService(new RoleManagerService(
mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
traceEnd();
// No dependency on Webview preparation in system server. But this should

View File

@@ -18,6 +18,8 @@ package com.android.internal.telephony;
import android.Manifest.permission;
import android.app.AppOpsManager;
import android.app.role.RoleManager;
import android.app.role.RoleManagerCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -29,13 +31,12 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Debug;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.telephony.Rlog;
@@ -50,6 +51,10 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Class for managing the primary application that we will deliver SMS/MMS messages to
@@ -67,6 +72,7 @@ public final class SmsApplication {
private static final String SCHEME_SMSTO = "smsto";
private static final String SCHEME_MMS = "mms";
private static final String SCHEME_MMSTO = "mmsto";
private static final boolean DEBUG = false;
private static final boolean DEBUG_MULTIUSER = false;
private static final int[] DEFAULT_APP_EXCLUSIVE_APPOPS = {
@@ -240,7 +246,11 @@ public final class SmsApplication {
// Get the list of apps registered for SMS
Intent intent = new Intent(Intents.SMS_DELIVER_ACTION);
List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
if (DEBUG) {
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
}
List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>();
@@ -266,7 +276,8 @@ public final class SmsApplication {
// Update any existing entries with mms receiver class
intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);
intent.setDataAndType(null, "application/vnd.wap.mms-message");
List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
for (ResolveInfo resolveInfo : mmsReceivers) {
final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -286,7 +297,8 @@ public final class SmsApplication {
// Update any existing entries with respond via message intent class.
intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
Uri.fromParts(SCHEME_SMSTO, "", null));
List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, 0,
List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
for (ResolveInfo resolveInfo : respondServices) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -306,7 +318,8 @@ public final class SmsApplication {
// Update any existing entries with supports send to.
intent = new Intent(Intent.ACTION_SENDTO,
Uri.fromParts(SCHEME_SMSTO, "", null));
List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, 0,
List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
for (ResolveInfo resolveInfo : sendToActivities) {
final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -323,7 +336,9 @@ public final class SmsApplication {
// Update any existing entries with the default sms changed handler.
intent = new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
List<ResolveInfo> smsAppChangedReceivers =
packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
packageManager.queryBroadcastReceiversAsUser(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" +
smsAppChangedReceivers);
@@ -348,7 +363,9 @@ public final class SmsApplication {
// Update any existing entries with the external provider changed handler.
intent = new Intent(Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE);
List<ResolveInfo> providerChangedReceivers =
packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
packageManager.queryBroadcastReceiversAsUser(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" +
providerChangedReceivers);
@@ -373,7 +390,9 @@ public final class SmsApplication {
// Update any existing entries with the sim full handler.
intent = new Intent(Intents.SIM_FULL_ACTION);
List<ResolveInfo> simFullReceivers =
packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
packageManager.queryBroadcastReceiversAsUser(intent,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers="
+ simFullReceivers);
@@ -406,7 +425,8 @@ public final class SmsApplication {
if (smsApplicationData != null) {
if (!smsApplicationData.isComplete()) {
Log.w(LOG_TAG, "Package " + packageName
+ " lacks required manifest declarations to be a default sms app");
+ " lacks required manifest declarations to be a default sms app: "
+ smsApplicationData);
receivers.remove(packageName);
}
}
@@ -418,7 +438,7 @@ public final class SmsApplication {
* Checks to see if we have a valid installed SMS application for the specified package name
* @return Data for the specified package name or null if there isn't one
*/
private static SmsApplicationData getApplicationForPackage(
public static SmsApplicationData getApplicationForPackage(
Collection<SmsApplicationData> applications, String packageName) {
if (packageName == null) {
return null;
@@ -456,8 +476,7 @@ public final class SmsApplication {
Log.i(LOG_TAG, "getApplication userId=" + userId);
}
// Determine which application receives the broadcast
String defaultApplication = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
String defaultApplication = getDefaultSmsPackage(context, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplication defaultApp=" + defaultApplication);
}
@@ -469,27 +488,6 @@ public final class SmsApplication {
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "getApplication appData=" + applicationData);
}
// Picking a new SMS app requires AppOps and Settings.Secure permissions, so we only do
// this if the caller asked us to.
if (updateIfNeeded && applicationData == null) {
// Try to find the default SMS package for this device
Resources r = context.getResources();
String defaultPackage =
r.getString(com.android.internal.R.string.default_sms_application);
applicationData = getApplicationForPackage(applications, defaultPackage);
if (applicationData == null) {
// Are there any applications?
if (applications.size() != 0) {
applicationData = (SmsApplicationData)applications.toArray()[0];
}
}
// If we found a new default app, update the setting
if (applicationData != null) {
setDefaultApplicationInternal(applicationData.mPackageName, context, userId);
}
}
// If we found a package, make sure AppOps permissions are set up correctly
if (applicationData != null) {
@@ -513,7 +511,7 @@ public final class SmsApplication {
// current SMS app will already be the preferred activity - but checking whether or
// not this is true is just as expensive as reconfiguring the preferred activity so
// we just reconfigure every time.
updateDefaultSmsApp(context, userId, applicationData);
defaultSmsAppChanged(context);
}
}
if (DEBUG_MULTIUSER) {
@@ -522,16 +520,17 @@ public final class SmsApplication {
return applicationData;
}
private static void updateDefaultSmsApp(Context context, int userId,
SmsApplicationData applicationData) {
private static String getDefaultSmsPackage(Context context, int userId) {
return context.getSystemService(RoleManager.class).getDefaultSmsPackage(userId);
}
/**
* Grants various permissions and appops on sms app change
*/
private static void defaultSmsAppChanged(Context context) {
PackageManager packageManager = context.getPackageManager();
AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
// Configure this as the preferred activity for SENDTO sms/mms intents
configurePreferredActivity(packageManager, new ComponentName(
applicationData.mPackageName, applicationData.mSendToClass),
userId);
// Assign permission to special system apps
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
PHONE_PACKAGE_NAME);
@@ -603,8 +602,7 @@ public final class SmsApplication {
final UserHandle userHandle = UserHandle.of(userId);
// Get old package name
String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
String oldPackageName = getDefaultSmsPackage(context, userId);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldPackageName +
@@ -636,16 +634,29 @@ public final class SmsApplication {
}
}
// Update the secure setting.
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName,
userId);
// Update the setting.
CompletableFuture<Void> res = new CompletableFuture<>();
context.getSystemService(RoleManager.class).addRoleHolderAsUser(
RoleManager.ROLE_SMS, applicationData.mPackageName, UserHandle.of(userId),
AsyncTask.THREAD_POOL_EXECUTOR, new RoleManagerCallback() {
@Override
public void onSuccess() {
res.complete(null);
}
// Allow relevant appops for the newly configured default SMS app.
setExclusiveAppops(applicationData.mPackageName, appOps, applicationData.mUid,
AppOpsManager.MODE_ALLOWED);
@Override
public void onFailure() {
res.completeExceptionally(new RuntimeException());
}
});
try {
res.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Log.e(LOG_TAG, "Exception while adding sms role holder " + applicationData, e);
return;
}
updateDefaultSmsApp(context, userId, applicationData);
defaultSmsAppChanged(context);
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);