Merge "Mirgate default SMS app handling to RoleManager"
This commit is contained in:
@@ -50,4 +50,6 @@ interface IRoleManager {
|
||||
boolean removeRoleHolderFromController(in String roleName, in String packageName);
|
||||
|
||||
List<String> getHeldRolesFromController(in String packageName);
|
||||
|
||||
String getDefaultSmsPackage(int userId);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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('|');
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user