Merge "Revert "Revert "[SettingsProvider] remove in-lock calls to PackageManager.getPackageUid()""" into sc-dev

This commit is contained in:
Songchun Fan
2021-04-13 21:21:31 +00:00
committed by Android (Google) Code Review
2 changed files with 154 additions and 172 deletions

View File

@@ -16,7 +16,6 @@
package com.android.providers.settings; package com.android.providers.settings;
import static android.os.Process.INVALID_UID;
import static android.os.Process.ROOT_UID; import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID; import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID; import static android.os.Process.SYSTEM_UID;
@@ -364,6 +363,11 @@ public class SettingsProvider extends ContentProvider {
mHandler = new Handler(mHandlerThread.getLooper()); mHandler = new Handler(mHandlerThread.getLooper());
mSettingsRegistry = new SettingsRegistry(); mSettingsRegistry = new SettingsRegistry();
} }
SettingsState.cacheSystemPackageNamesAndSystemSignature(getContext());
synchronized (mLock) {
mSettingsRegistry.migrateAllLegacySettingsIfNeededLocked();
mSettingsRegistry.syncSsaidTableOnStartLocked();
}
mHandler.post(() -> { mHandler.post(() -> {
registerBroadcastReceivers(); registerBroadcastReceivers();
startWatchingUserRestrictionChanges(); startWatchingUserRestrictionChanges();
@@ -2499,8 +2503,6 @@ public class SettingsProvider extends ContentProvider {
mHandler = new MyHandler(getContext().getMainLooper()); mHandler = new MyHandler(getContext().getMainLooper());
mGenerationRegistry = new GenerationRegistry(mLock); mGenerationRegistry = new GenerationRegistry(mLock);
mBackupManager = new BackupManager(getContext()); mBackupManager = new BackupManager(getContext());
migrateAllLegacySettingsIfNeeded();
syncSsaidTableOnStart();
} }
private void generateUserKeyLocked(int userId) { private void generateUserKeyLocked(int userId) {
@@ -2587,38 +2589,36 @@ public class SettingsProvider extends ContentProvider {
return getSettingLocked(SETTINGS_TYPE_SSAID, userId, uid); return getSettingLocked(SETTINGS_TYPE_SSAID, userId, uid);
} }
public void syncSsaidTableOnStart() { private void syncSsaidTableOnStartLocked() {
synchronized (mLock) { // Verify that each user's packages and ssaid's are in sync.
// Verify that each user's packages and ssaid's are in sync. for (UserInfo user : mUserManager.getAliveUsers()) {
for (UserInfo user : mUserManager.getAliveUsers()) { // Get all uids for the user's packages.
// Get all uids for the user's packages. final List<PackageInfo> packages;
final List<PackageInfo> packages; try {
try { packages = mPackageManager.getInstalledPackages(
packages = mPackageManager.getInstalledPackages(
PackageManager.MATCH_UNINSTALLED_PACKAGES, PackageManager.MATCH_UNINSTALLED_PACKAGES,
user.id).getList(); user.id).getList();
} catch (RemoteException e) { } catch (RemoteException e) {
throw new IllegalStateException("Package manager not available"); throw new IllegalStateException("Package manager not available");
} }
final Set<String> appUids = new HashSet<>(); final Set<String> appUids = new HashSet<>();
for (PackageInfo info : packages) { for (PackageInfo info : packages) {
appUids.add(Integer.toString(info.applicationInfo.uid)); appUids.add(Integer.toString(info.applicationInfo.uid));
} }
// Get all uids currently stored in the user's ssaid table. // Get all uids currently stored in the user's ssaid table.
final Set<String> ssaidUids = new HashSet<>( final Set<String> ssaidUids = new HashSet<>(
getSettingsNamesLocked(SETTINGS_TYPE_SSAID, user.id)); getSettingsNamesLocked(SETTINGS_TYPE_SSAID, user.id));
ssaidUids.remove(SSAID_USER_KEY); ssaidUids.remove(SSAID_USER_KEY);
// Perform a set difference for the appUids and ssaidUids. // Perform a set difference for the appUids and ssaidUids.
ssaidUids.removeAll(appUids); ssaidUids.removeAll(appUids);
// If there are ssaidUids left over they need to be removed from the table. // If there are ssaidUids left over they need to be removed from the table.
final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID,
user.id); user.id);
for (String uid : ssaidUids) { for (String uid : ssaidUids) {
ssaidSettings.deleteSettingLocked(uid); ssaidSettings.deleteSettingLocked(uid);
}
} }
} }
} }
@@ -2911,7 +2911,7 @@ public class SettingsProvider extends ContentProvider {
boolean someSettingChanged = false; boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name); Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(), if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName(), INVALID_UID, userId)) { setting.getPackageName())) {
if (prefix != null && !setting.getName().startsWith(prefix)) { if (prefix != null && !setting.getName().startsWith(prefix)) {
continue; continue;
} }
@@ -2931,7 +2931,7 @@ public class SettingsProvider extends ContentProvider {
boolean someSettingChanged = false; boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name); Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(), if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName(), INVALID_UID, userId)) { setting.getPackageName())) {
if (prefix != null && !setting.getName().startsWith(prefix)) { if (prefix != null && !setting.getName().startsWith(prefix)) {
continue; continue;
} }
@@ -3009,40 +3009,38 @@ public class SettingsProvider extends ContentProvider {
return mSettingsStates.get(key); return mSettingsStates.get(key);
} }
private void migrateAllLegacySettingsIfNeeded() { private void migrateAllLegacySettingsIfNeededLocked() {
synchronized (mLock) { final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM); File globalFile = getSettingsFile(key);
File globalFile = getSettingsFile(key); if (SettingsState.stateFileExists(globalFile)) {
if (SettingsState.stateFileExists(globalFile)) { return;
return; }
}
mSettingsCreationBuildId = Build.ID; mSettingsCreationBuildId = Build.ID;
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
List<UserInfo> users = mUserManager.getAliveUsers(); List<UserInfo> users = mUserManager.getAliveUsers();
final int userCount = users.size(); final int userCount = users.size();
for (int i = 0; i < userCount; i++) { for (int i = 0; i < userCount; i++) {
final int userId = users.get(i).id; final int userId = users.get(i).id;
DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId); DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
SQLiteDatabase database = dbHelper.getWritableDatabase(); SQLiteDatabase database = dbHelper.getWritableDatabase();
migrateLegacySettingsForUserLocked(dbHelper, database, userId); migrateLegacySettingsForUserLocked(dbHelper, database, userId);
// Upgrade to the latest version. // Upgrade to the latest version.
UpgradeController upgrader = new UpgradeController(userId); UpgradeController upgrader = new UpgradeController(userId);
upgrader.upgradeIfNeededLocked(); upgrader.upgradeIfNeededLocked();
// Drop from memory if not a running user. // Drop from memory if not a running user.
if (!mUserManager.isUserRunning(new UserHandle(userId))) { if (!mUserManager.isUserRunning(new UserHandle(userId))) {
removeUserStateLocked(userId, false); removeUserStateLocked(userId, false);
}
} }
} finally {
Binder.restoreCallingIdentity(identity);
} }
} finally {
Binder.restoreCallingIdentity(identity);
} }
} }
@@ -5036,19 +5034,9 @@ public class SettingsProvider extends ContentProvider {
// In the upgrade case we pretend the call is made from the app // In the upgrade case we pretend the call is made from the app
// that made the last change to the setting to properly determine // that made the last change to the setting to properly determine
// whether the call has been made by a system component. // whether the call has been made by a system component.
int callingUid = -1;
try { try {
callingUid = mPackageManager.getPackageUid(setting.getPackageName(), 0, userId); final boolean systemSet = SettingsState.isSystemPackage(
} catch (RemoteException e) { getContext(), setting.getPackageName());
/* ignore - handled below */
}
if (callingUid < 0) {
Slog.e(LOG_TAG, "Unknown package: " + setting.getPackageName());
continue;
}
try {
final boolean systemSet = SettingsState.isSystemPackage(getContext(),
setting.getPackageName(), callingUid, userId);
if (systemSet) { if (systemSet) {
settings.insertSettingOverrideableByRestoreLocked(name, setting.getValue(), settings.insertSettingOverrideableByRestoreLocked(name, setting.getValue(),
setting.getTag(), true, setting.getPackageName()); setting.getTag(), true, setting.getPackageName());

View File

@@ -17,14 +17,13 @@
package com.android.providers.settings; package com.android.providers.settings;
import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.INVALID_UID;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.FileUtils; import android.os.FileUtils;
@@ -37,10 +36,10 @@ import android.provider.Settings;
import android.providers.settings.SettingsOperationProto; import android.providers.settings.SettingsOperationProto;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile; import android.util.AtomicFile;
import android.util.Base64; import android.util.Base64;
import android.util.Slog; import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TimeUtils; import android.util.TimeUtils;
import android.util.TypedXmlPullParser; import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer; import android.util.TypedXmlSerializer;
@@ -149,13 +148,7 @@ final class SettingsState {
private static final String NULL_VALUE = "null"; private static final String NULL_VALUE = "null";
private static final Object sLock = new Object(); private static final ArraySet<String> sSystemPackages = new ArraySet<>();
@GuardedBy("sLock")
private static final SparseIntArray sSystemUids = new SparseIntArray();
@GuardedBy("sLock")
private static Signature sSystemSignature;
private final Object mWriteLock = new Object(); private final Object mWriteLock = new Object();
@@ -641,7 +634,7 @@ final class SettingsState {
/** /**
* Dump historical operations as a proto buf. * Dump historical operations as a proto buf.
* *
* @param proto The proto buf stream to dump to * @param proto The proto buf stream to dump to
* @param fieldId The repeated field ID to use to save an operation to. * @param fieldId The repeated field ID to use to save an operation to.
*/ */
void dumpHistoricalOperations(@NonNull ProtoOutputStream proto, long fieldId) { void dumpHistoricalOperations(@NonNull ProtoOutputStream proto, long fieldId) {
@@ -1048,6 +1041,7 @@ final class SettingsState {
/** /**
* Uses AtomicFile to check if the file or its backup exists. * Uses AtomicFile to check if the file or its backup exists.
*
* @param file The file to check for existence * @param file The file to check for existence
* @return whether the original or backup exist * @return whether the original or backup exist
*/ */
@@ -1307,9 +1301,9 @@ final class SettingsState {
if (NULL_VALUE.equals(value)) { if (NULL_VALUE.equals(value)) {
value = null; value = null;
} }
final boolean callerSystem = !forceNonSystemPackage && final boolean callerSystem = !forceNonSystemPackage &&
!isNull() && isSystemPackage(mContext, packageName); !isNull() && (isCalledFromSystem(packageName)
|| isSystemPackage(mContext, packageName));
// Settings set by the system are always defaults. // Settings set by the system are always defaults.
if (callerSystem) { if (callerSystem) {
setDefault = true; setDefault = true;
@@ -1434,98 +1428,98 @@ final class SettingsState {
return sb.toString(); return sb.toString();
} }
// Check if a specific package belonging to the caller is part of the system package. // Cache the list of names of system packages. This is only called once on system boot.
public static boolean isSystemPackage(Context context, String packageName) { public static void cacheSystemPackageNamesAndSystemSignature(@NonNull Context context) {
final int callingUid = Binder.getCallingUid(); final PackageManager packageManager = context.getPackageManager();
final int callingUserId = UserHandle.getUserId(callingUid); final long identity = Binder.clearCallingIdentity();
return isSystemPackage(context, packageName, callingUid, callingUserId); try {
} sSystemPackages.add(SYSTEM_PACKAGE_NAME);
// Cache SetupWizard package name.
// Check if a specific package, uid, and user ID are part of the system package. final String setupWizPackageName = packageManager.getSetupWizardPackageName();
public static boolean isSystemPackage(Context context, String packageName, int uid, if (setupWizPackageName != null) {
int userId) { sSystemPackages.add(setupWizPackageName);
synchronized (sLock) {
if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
return true;
} }
final List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
// Shell and Root are not considered a part of the system final int installedPackagesCount = packageInfos.size();
if (SHELL_PACKAGE_NAME.equals(packageName) for (int i = 0; i < installedPackagesCount; i++) {
|| ROOT_PACKAGE_NAME.equals(packageName)) { if (shouldAddToSystemPackages(packageInfos.get(i))) {
return false; sSystemPackages.add(packageInfos.get(i).packageName);
}
if (uid != INVALID_UID) {
// Native services running as a special UID get a pass
final int callingAppId = UserHandle.getAppId(uid);
if (callingAppId < FIRST_APPLICATION_UID) {
sSystemUids.put(callingAppId, callingAppId);
return true;
} }
} }
} finally {
final long identity = Binder.clearCallingIdentity(); Binder.restoreCallingIdentity(identity);
try {
try {
uid = context.getPackageManager().getPackageUidAsUser(packageName, 0, userId);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
// If the system or a special system UID (like telephony), done.
if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) {
sSystemUids.put(uid, uid);
return true;
}
// If already known system component, done.
if (sSystemUids.indexOfKey(uid) >= 0) {
return true;
}
// If SetupWizard, done.
String setupWizPackage = context.getPackageManager().getSetupWizardPackageName();
if (packageName.equals(setupWizPackage)) {
sSystemUids.put(uid, uid);
return true;
}
// If a persistent system app, done.
PackageInfo packageInfo;
try {
packageInfo = context.getPackageManager().getPackageInfoAsUser(
packageName, PackageManager.GET_SIGNATURES, userId);
if ((packageInfo.applicationInfo.flags
& ApplicationInfo.FLAG_PERSISTENT) != 0
&& (packageInfo.applicationInfo.flags
& ApplicationInfo.FLAG_SYSTEM) != 0) {
sSystemUids.put(uid, uid);
return true;
}
} catch (PackageManager.NameNotFoundException e) {
return false;
}
// Last check if system signed.
if (sSystemSignature == null) {
try {
sSystemSignature = context.getPackageManager().getPackageInfoAsUser(
SYSTEM_PACKAGE_NAME, PackageManager.GET_SIGNATURES,
UserHandle.USER_SYSTEM).signatures[0];
} catch (PackageManager.NameNotFoundException e) {
/* impossible */
return false;
}
}
if (sSystemSignature.equals(packageInfo.signatures[0])) {
sSystemUids.put(uid, uid);
return true;
}
} finally {
Binder.restoreCallingIdentity(identity);
}
return false;
} }
} }
private static boolean shouldAddToSystemPackages(@NonNull PackageInfo packageInfo) {
// Shell and Root are not considered a part of the system
if (isShellOrRoot(packageInfo.packageName)) {
return false;
}
// Already added
if (sSystemPackages.contains(packageInfo.packageName)) {
return false;
}
return isSystemPackage(packageInfo.applicationInfo);
}
private static boolean isShellOrRoot(@NonNull String packageName) {
return (SHELL_PACKAGE_NAME.equals(packageName)
|| ROOT_PACKAGE_NAME.equals(packageName));
}
private static boolean isCalledFromSystem(@NonNull String packageName) {
// Shell and Root are not considered a part of the system
if (isShellOrRoot(packageName)) {
return false;
}
final int callingUid = Binder.getCallingUid();
// Native services running as a special UID get a pass
final int callingAppId = UserHandle.getAppId(callingUid);
return (callingAppId < FIRST_APPLICATION_UID);
}
public static boolean isSystemPackage(@NonNull Context context, @NonNull String packageName) {
// Check shell or root before trying to retrieve ApplicationInfo to fail fast
if (isShellOrRoot(packageName)) {
return false;
}
// If it's a known system package or known to be platform signed
if (sSystemPackages.contains(packageName)) {
return true;
}
ApplicationInfo aInfo = null;
final long identity = Binder.clearCallingIdentity();
try {
try {
// Notice that this makes a call to package manager inside the lock
aInfo = context.getPackageManager().getApplicationInfo(packageName, 0);
} catch (PackageManager.NameNotFoundException ignored) {
}
} finally {
Binder.restoreCallingIdentity(identity);
}
return isSystemPackage(aInfo);
}
private static boolean isSystemPackage(@Nullable ApplicationInfo aInfo) {
if (aInfo == null) {
return false;
}
// If the system or a special system UID (like telephony), done.
if (aInfo.uid < FIRST_APPLICATION_UID) {
return true;
}
// If a persistent system app, done.
if ((aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
&& (aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
// Platform signed packages are considered to be from the system
if (aInfo.isSignedWithPlatformKey()) {
return true;
}
return false;
}
} }