From ce2a80437d196e6f05ea0a63b61141db6598f01b Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Wed, 13 Jan 2021 02:21:10 -0800 Subject: [PATCH] Use a single interface for reading pre-Q and pre-S role state. The logic to read the platform XML is moved from RoleUserState. The logic to read legacy settings is left untouched except refactored to return the mapping at once. Bug: 158736025 Test: presubmit Change-Id: Ifd1770bf869ea77b2f8a4ff8b3eae46a46cc90cf --- .../role/LegacyRoleResolutionPolicy.java | 171 ---------- .../role/LegacyRoleStateProviderImpl.java | 291 ++++++++++++++++++ ...ider.java => LegacyRoleStateProvider.java} | 23 +- .../server/role/RoleManagerService.java | 35 +-- .../android/server/role/RoleUserState.java | 131 ++------ .../java/com/android/server/SystemServer.java | 4 +- 6 files changed, 329 insertions(+), 326 deletions(-) delete mode 100644 services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java create mode 100644 services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java rename services/core/java/com/android/server/role/{LegacyRoleHolderProvider.java => LegacyRoleStateProvider.java} (58%) diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java deleted file mode 100644 index b95c5efca6d52..0000000000000 --- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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.annotation.UserIdInt; -import android.app.role.RoleManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; -import android.content.pm.ResolveInfo; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.Slog; - -import com.android.internal.R; -import com.android.internal.telephony.SmsApplication; -import com.android.internal.util.CollectionUtils; -import com.android.server.LocalServices; -import com.android.server.role.LegacyRoleHolderProvider; -import com.android.server.role.RoleManagerService; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * 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 LegacyRoleHolderProvider { - - private static final boolean DEBUG = false; - private static final String LOG_TAG = "LegacyRoleResolutionPol"; - - @NonNull - private final Context mContext; - - public LegacyRoleResolutionPolicy(@NonNull Context context) { - mContext = context; - } - - @NonNull - @Override - public List getLegacyRoleHolders(@NonNull String roleName, @UserIdInt int userId) { - switch (roleName) { - case RoleManager.ROLE_ASSISTANT: { - String packageName; - String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), - Settings.Secure.ASSISTANT, userId); - // AssistUtils was using the default assistant app if Settings.Secure.ASSISTANT is - // null, while only an empty string means user selected "None". - if (setting != null) { - if (!setting.isEmpty()) { - ComponentName componentName = ComponentName.unflattenFromString(setting); - packageName = componentName != null ? componentName.getPackageName() : null; - } else { - packageName = null; - } - } else if (mContext.getPackageManager().isDeviceUpgrading()) { - String defaultAssistant = mContext.getString(R.string.config_defaultAssistant); - packageName = !TextUtils.isEmpty(defaultAssistant) ? defaultAssistant : null; - } else { - packageName = null; - } - return CollectionUtils.singletonOrEmpty(packageName); - } - case RoleManager.ROLE_BROWSER: { - PackageManagerInternal packageManagerInternal = LocalServices.getService( - PackageManagerInternal.class); - String packageName = packageManagerInternal.removeLegacyDefaultBrowserPackageName( - userId); - return CollectionUtils.singletonOrEmpty(packageName); - } - case RoleManager.ROLE_DIALER: { - String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), - Settings.Secure.DIALER_DEFAULT_APPLICATION, userId); - String packageName; - if (!TextUtils.isEmpty(setting)) { - packageName = setting; - } else if (mContext.getPackageManager().isDeviceUpgrading()) { - // DefaultDialerManager was using the default dialer app if - // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid. - // TelecomManager.getSystemDialerPackage() won't work because it might not - // be ready. - packageName = mContext.getString(R.string.config_defaultDialer); - } else { - packageName = null; - } - return CollectionUtils.singletonOrEmpty(packageName); - } - case RoleManager.ROLE_SMS: { - String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), - Settings.Secure.SMS_DEFAULT_APPLICATION, userId); - String packageName; - if (!TextUtils.isEmpty(setting)) { - packageName = setting; - } else if (mContext.getPackageManager().isDeviceUpgrading()) { - // SmsApplication was using the default SMS app if - // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid. - packageName = mContext.getString(R.string.config_defaultSms); - } else { - packageName = null; - } - return CollectionUtils.singletonOrEmpty(packageName); - } - case RoleManager.ROLE_HOME: { - PackageManager packageManager = mContext.getPackageManager(); - String packageName; - if (packageManager.isDeviceUpgrading()) { - ResolveInfo resolveInfo = packageManager.resolveActivityAsUser( - new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), - PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); - packageName = resolveInfo != null && resolveInfo.activityInfo != null - ? resolveInfo.activityInfo.packageName : null; - if (packageName != null && isSettingsApplication(packageName, userId)) { - packageName = null; - } - } else { - packageName = null; - } - return CollectionUtils.singletonOrEmpty(packageName); - } - case RoleManager.ROLE_EMERGENCY: { - String defaultEmergencyApp = Settings.Secure.getStringForUser( - mContext.getContentResolver(), - Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, userId); - return CollectionUtils.singletonOrEmpty(defaultEmergencyApp); - } - default: { - Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName); - return Collections.emptyList(); - } - } - } - - private boolean isSettingsApplication(@NonNull String packageName, @UserIdInt int userId) { - PackageManager packageManager = mContext.getPackageManager(); - ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(new Intent( - Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); - if (resolveInfo == null || resolveInfo.activityInfo == null) { - return false; - } - return Objects.equals(packageName, resolveInfo.activityInfo.packageName); - } -} diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java b/services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java new file mode 100644 index 0000000000000..097f332a2637e --- /dev/null +++ b/services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java @@ -0,0 +1,291 @@ +/* + * 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.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.role.RoleManager; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; +import android.content.pm.ResolveInfo; +import android.os.Environment; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.AtomicFile; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.R; +import com.android.server.LocalServices; +import com.android.server.role.LegacyRoleStateProvider; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Implementation to provide legacy role state. + */ +public class LegacyRoleStateProviderImpl implements LegacyRoleStateProvider { + private static final String LOG_TAG = "LegacyRoleState"; + + private static final String ROLES_FILE_NAME = "roles.xml"; + + private static final String TAG_ROLES = "roles"; + private static final String TAG_ROLE = "role"; + private static final String TAG_HOLDER = "holder"; + private static final String ATTRIBUTE_NAME = "name"; + + @NonNull + private final Context mContext; + + public LegacyRoleStateProviderImpl(@NonNull Context context) { + mContext = context; + } + + @NonNull + @Override + public Map> getLegacyRoleState(@UserIdInt int userId) { + Map> roles = readFile(userId); + if (roles == null) { + roles = readFromLegacySettings(userId); + } + return roles; + } + + @Nullable + private Map> readFile(@UserIdInt int userId) { + File file = getFile(userId); + try (FileInputStream in = new AtomicFile(file).openRead()) { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(in, null); + Map> roles = parseXml(parser); + Slog.i(LOG_TAG, "Read legacy roles.xml successfully"); + return roles; + } catch (FileNotFoundException e) { + Slog.i(LOG_TAG, "Legacy roles.xml not found"); + return null; + } catch (XmlPullParserException | IOException e) { + Slog.wtf(LOG_TAG, "Failed to parse legacy roles.xml: " + file, e); + return null; + } + } + + @NonNull + private Map> parseXml(@NonNull XmlPullParser parser) throws IOException, + XmlPullParserException { + int type; + int depth; + int innerDepth = parser.getDepth() + 1; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { + if (depth > innerDepth || type != XmlPullParser.START_TAG) { + continue; + } + + if (parser.getName().equals(TAG_ROLES)) { + return parseRoles(parser); + } + } + + throw new IOException("Missing <" + TAG_ROLES + "> in roles.xml"); + } + + @NonNull + private Map> parseRoles(@NonNull XmlPullParser parser) throws IOException, + XmlPullParserException { + Map> roles = new ArrayMap<>(); + + int type; + int depth; + int innerDepth = parser.getDepth() + 1; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { + if (depth > innerDepth || type != XmlPullParser.START_TAG) { + continue; + } + + if (parser.getName().equals(TAG_ROLE)) { + String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME); + Set roleHolders = parseRoleHoldersLocked(parser); + roles.put(roleName, roleHolders); + } + } + + return roles; + } + + @NonNull + private Set parseRoleHoldersLocked(@NonNull XmlPullParser parser) + throws IOException, XmlPullParserException { + Set roleHolders = new ArraySet<>(); + + int type; + int depth; + int innerDepth = parser.getDepth() + 1; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { + if (depth > innerDepth || type != XmlPullParser.START_TAG) { + continue; + } + + if (parser.getName().equals(TAG_HOLDER)) { + String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME); + roleHolders.add(roleHolder); + } + } + + return roleHolders; + } + + @NonNull + private static File getFile(@UserIdInt int userId) { + return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME); + } + + @NonNull + private Map> readFromLegacySettings(@UserIdInt int userId) { + Map> roles = new ArrayMap<>(); + + // Assistant + ContentResolver contentResolver = mContext.getContentResolver(); + String assistantSetting = Settings.Secure.getStringForUser(contentResolver, + Settings.Secure.ASSISTANT, userId); + PackageManager packageManager = mContext.getPackageManager(); + String assistantPackageName; + // AssistUtils was using the default assistant app if Settings.Secure.ASSISTANT is + // null, while only an empty string means user selected "None". + if (assistantSetting != null) { + if (!assistantSetting.isEmpty()) { + ComponentName componentName = ComponentName.unflattenFromString(assistantSetting); + assistantPackageName = componentName != null ? componentName.getPackageName() + : null; + } else { + assistantPackageName = null; + } + } else if (packageManager.isDeviceUpgrading()) { + String defaultAssistant = mContext.getString(R.string.config_defaultAssistant); + assistantPackageName = !TextUtils.isEmpty(defaultAssistant) ? defaultAssistant : null; + } else { + assistantPackageName = null; + } + if (assistantPackageName != null) { + roles.put(RoleManager.ROLE_ASSISTANT, Collections.singleton(assistantPackageName)); + } + + // Browser + PackageManagerInternal packageManagerInternal = LocalServices.getService( + PackageManagerInternal.class); + String browserPackageName = packageManagerInternal.removeLegacyDefaultBrowserPackageName( + userId); + if (browserPackageName != null) { + roles.put(RoleManager.ROLE_BROWSER, Collections.singleton(browserPackageName)); + } + + // Dialer + String dialerSetting = Settings.Secure.getStringForUser(contentResolver, + Settings.Secure.DIALER_DEFAULT_APPLICATION, userId); + String dialerPackageName; + if (!TextUtils.isEmpty(dialerSetting)) { + dialerPackageName = dialerSetting; + } else if (packageManager.isDeviceUpgrading()) { + // DefaultDialerManager was using the default dialer app if + // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid. + // TelecomManager.getSystemDialerPackage() won't work because it might not + // be ready. + dialerPackageName = mContext.getString(R.string.config_defaultDialer); + } else { + dialerPackageName = null; + } + if (dialerPackageName != null) { + roles.put(RoleManager.ROLE_DIALER, Collections.singleton(dialerPackageName)); + } + + // SMS + String smsSetting = Settings.Secure.getStringForUser(contentResolver, + Settings.Secure.SMS_DEFAULT_APPLICATION, userId); + String smsPackageName; + if (!TextUtils.isEmpty(smsSetting)) { + smsPackageName = smsSetting; + } else if (mContext.getPackageManager().isDeviceUpgrading()) { + // SmsApplication was using the default SMS app if + // Settings.Secure.DIALER_DEFAULT_APPLICATION is invalid. + smsPackageName = mContext.getString(R.string.config_defaultSms); + } else { + smsPackageName = null; + } + if (smsPackageName != null) { + roles.put(RoleManager.ROLE_SMS, Collections.singleton(smsPackageName)); + } + + // Home + String homePackageName; + if (packageManager.isDeviceUpgrading()) { + ResolveInfo resolveInfo = packageManager.resolveActivityAsUser( + new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME), + PackageManager.MATCH_DEFAULT_ONLY + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + homePackageName = resolveInfo != null && resolveInfo.activityInfo != null + ? resolveInfo.activityInfo.packageName : null; + if (homePackageName != null && isSettingsApplication(homePackageName, userId)) { + homePackageName = null; + } + } else { + homePackageName = null; + } + if (homePackageName != null) { + roles.put(RoleManager.ROLE_HOME, Collections.singleton(homePackageName)); + } + + // Emergency + String emergencyPackageName = Settings.Secure.getStringForUser(contentResolver, + Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION, userId); + if (emergencyPackageName != null) { + roles.put(RoleManager.ROLE_EMERGENCY, Collections.singleton(emergencyPackageName)); + } + + return roles; + } + + private boolean isSettingsApplication(@NonNull String packageName, @UserIdInt int userId) { + PackageManager packageManager = mContext.getPackageManager(); + ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(new Intent( + Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + if (resolveInfo == null || resolveInfo.activityInfo == null) { + return false; + } + return Objects.equals(packageName, resolveInfo.activityInfo.packageName); + } +} diff --git a/services/core/java/com/android/server/role/LegacyRoleHolderProvider.java b/services/core/java/com/android/server/role/LegacyRoleStateProvider.java similarity index 58% rename from services/core/java/com/android/server/role/LegacyRoleHolderProvider.java rename to services/core/java/com/android/server/role/LegacyRoleStateProvider.java index ed0d67563132a..ec4cfc176a8d7 100644 --- a/services/core/java/com/android/server/role/LegacyRoleHolderProvider.java +++ b/services/core/java/com/android/server/role/LegacyRoleStateProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 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. @@ -19,22 +19,25 @@ package com.android.server.role; import android.annotation.NonNull; import android.annotation.UserIdInt; -import java.util.List; +import java.util.Map; +import java.util.Set; /** - * A provider for migrating legacy "role"s to their actual role implementation. + * Provider for legacy role state. + *

+ * The role state may come from two sources, either the different pre-role default app settings, or + * the pre-modularization roles.xml file stored in platform. + * + * @hide */ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER) -public interface LegacyRoleHolderProvider { +public interface LegacyRoleStateProvider { /** - * Get the list of holders of a legacy "role" before its actual role is introduced. - *

- * This method will only be called for the first time a role is made available in the platform. + * Get the legacy role state stored in the platform. * - * @param roleName the name of the role * @param userId the user ID - * @return a list of holders for the given role + * @return a mapping of role name to its set of holders */ @NonNull - List getLegacyRoleHolders(@NonNull String roleName, @UserIdInt int userId); + Map> getLegacyRoleState(@UserIdInt int userId); } diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index 4e42f16b68bf3..79f22b190b322 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -103,7 +103,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C private final Object mLock = new Object(); @NonNull - private final LegacyRoleHolderProvider mLegacyRoleHolderProvider; + private final LegacyRoleStateProvider mLegacyRoleStateProvider; /** * Maps user id to its state. @@ -139,10 +139,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C new SparseArray<>(); public RoleManagerService(@NonNull Context context, - @NonNull LegacyRoleHolderProvider legacyRoleHolderProvider) { + @NonNull LegacyRoleStateProvider legacyRoleStateProvider) { super(context); - mLegacyRoleHolderProvider = legacyRoleHolderProvider; + mLegacyRoleStateProvider = legacyRoleStateProvider; RoleControllerManager.initializeRemoteServiceComponentName(context); @@ -241,16 +241,6 @@ public class RoleManagerService extends SystemService implements RoleUserState.C return AndroidFuture.completedFuture(null); } - //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 - maybeMigrateRole(RoleManager.ROLE_ASSISTANT, userId); - maybeMigrateRole(RoleManager.ROLE_BROWSER, userId); - maybeMigrateRole(RoleManager.ROLE_DIALER, userId); - maybeMigrateRole(RoleManager.ROLE_SMS, userId); - maybeMigrateRole(RoleManager.ROLE_EMERGENCY, userId); - maybeMigrateRole(RoleManager.ROLE_HOME, userId); - // Some package state has changed, so grant default roles again. Slog.i(LOG_TAG, "Granting default roles..."); AndroidFuture future = new AndroidFuture<>(); @@ -266,23 +256,6 @@ public class RoleManagerService extends SystemService implements RoleUserState.C return future; } - private void maybeMigrateRole(String role, @UserIdInt int userId) { - // Any role for which we have a record are already migrated - RoleUserState userState = getOrCreateUserState(userId); - if (!userState.isRoleAvailable(role)) { - List roleHolders = mLegacyRoleHolderProvider.getLegacyRoleHolders(role, userId); - if (roleHolders.isEmpty()) { - return; - } - Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders); - userState.addRoleName(role); - int size = roleHolders.size(); - for (int i = 0; i < size; i++) { - userState.addRoleHolder(role, roleHolders.get(i)); - } - } - } - @Nullable private String computePackageStateHash(@UserIdInt int userId) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); @@ -327,7 +300,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C synchronized (mLock) { RoleUserState userState = mUserStates.get(userId); if (userState == null) { - userState = new RoleUserState(userId, this); + userState = new RoleUserState(userId, mLegacyRoleStateProvider, this); mUserStates.put(userId, userState); } return userState; diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java index 3a5ed5c6425fa..f5a79eabaf5ae 100644 --- a/services/core/java/com/android/server/role/RoleUserState.java +++ b/services/core/java/com/android/server/role/RoleUserState.java @@ -21,14 +21,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; -import android.os.Environment; import android.os.Handler; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.AtomicFile; import android.util.Slog; -import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; @@ -38,13 +35,6 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.role.persistence.RolesPersistence; import com.android.role.persistence.RolesState; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -59,22 +49,16 @@ class RoleUserState { public static final int VERSION_UNDEFINED = -1; - private static final String ROLES_FILE_NAME = "roles.xml"; - private static final long WRITE_DELAY_MILLIS = 200; - private static final String TAG_ROLES = "roles"; - private static final String TAG_ROLE = "role"; - private static final String TAG_HOLDER = "holder"; - private static final String ATTRIBUTE_VERSION = "version"; - private static final String ATTRIBUTE_NAME = "name"; - private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash"; - private final RolesPersistence mPersistence = RolesPersistence.createInstance(); @UserIdInt private final int mUserId; + @NonNull + private final LegacyRoleStateProvider mLegacyStateProvider; + @NonNull private final Callback mCallback; @@ -108,10 +92,13 @@ class RoleUserState { * Create a new user state, and read its state from disk if previously persisted. * * @param userId the user id for this user state + * @param legacyStateProvider the provider for legacy role state * @param callback the callback for this user state */ - public RoleUserState(@UserIdInt int userId, @NonNull Callback callback) { + public RoleUserState(@UserIdInt int userId, + @NonNull LegacyRoleStateProvider legacyStateProvider, @NonNull Callback callback) { mUserId = userId; + mLegacyStateProvider = legacyStateProvider; mCallback = callback; readFile(); @@ -368,102 +355,27 @@ class RoleUserState { private void readFile() { synchronized (mLock) { - RolesState roles = mPersistence.readForUser(UserHandle.of(mUserId)); - if (roles == null) { - readLegacyFileLocked(); - scheduleWriteFileLocked(); - return; + RolesState roleState = mPersistence.readForUser(UserHandle.of(mUserId)); + + Map> roles; + if (roleState != null) { + mVersion = roleState.getVersion(); + mPackagesHash = roleState.getPackagesHash(); + roles = roleState.getRoles(); + } else { + roles = mLegacyStateProvider.getLegacyRoleState(mUserId); } - - mVersion = roles.getVersion(); - mPackagesHash = roles.getPackagesHash(); - mRoles.clear(); - for (Map.Entry> entry : roles.getRoles().entrySet()) { + for (Map.Entry> entry : roles.entrySet()) { String roleName = entry.getKey(); ArraySet roleHolders = new ArraySet<>(entry.getValue()); mRoles.put(roleName, roleHolders); } - } - } - private void readLegacyFileLocked() { - File file = getFile(mUserId); - try (FileInputStream in = new AtomicFile(file).openRead()) { - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(in, null); - parseXmlLocked(parser); - Slog.i(LOG_TAG, "Read roles.xml successfully"); - } catch (FileNotFoundException e) { - Slog.i(LOG_TAG, "roles.xml not found"); - } catch (XmlPullParserException | IOException e) { - throw new IllegalStateException("Failed to parse roles.xml: " + file, e); - } - } - - private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException, - XmlPullParserException { - int type; - int depth; - int innerDepth = parser.getDepth() + 1; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { - if (depth > innerDepth || type != XmlPullParser.START_TAG) { - continue; - } - - if (parser.getName().equals(TAG_ROLES)) { - parseRolesLocked(parser); - return; + if (roleState == null) { + scheduleWriteFileLocked(); } } - Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml"); - } - - private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException, - XmlPullParserException { - mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION)); - mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH); - mRoles.clear(); - - int type; - int depth; - int innerDepth = parser.getDepth() + 1; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { - if (depth > innerDepth || type != XmlPullParser.START_TAG) { - continue; - } - - if (parser.getName().equals(TAG_ROLE)) { - String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME); - ArraySet roleHolders = parseRoleHoldersLocked(parser); - mRoles.put(roleName, roleHolders); - } - } - } - - @NonNull - private ArraySet parseRoleHoldersLocked(@NonNull XmlPullParser parser) - throws IOException, XmlPullParserException { - ArraySet roleHolders = new ArraySet<>(); - - int type; - int depth; - int innerDepth = parser.getDepth() + 1; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { - if (depth > innerDepth || type != XmlPullParser.START_TAG) { - continue; - } - - if (parser.getName().equals(TAG_HOLDER)) { - String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME); - roleHolders.add(roleHolder); - } - } - - return roleHolders; } /** @@ -549,11 +461,6 @@ class RoleUserState { } } - @NonNull - private static File getFile(@UserIdInt int userId) { - return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME); - } - /** * Callback for a user state. */ diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 94df1851aa874..57b3e8da88857 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -160,7 +160,7 @@ import com.android.server.pm.UserManagerService; import com.android.server.pm.dex.SystemServerDexLoadReporter; import com.android.server.policy.PermissionPolicyService; import com.android.server.policy.PhoneWindowManager; -import com.android.server.policy.role.LegacyRoleResolutionPolicy; +import com.android.server.policy.role.LegacyRoleStateProviderImpl; import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; import com.android.server.power.ThermalManagerService; @@ -2021,7 +2021,7 @@ public final class SystemServer implements Dumpable { // Grants default permissions and defines roles t.traceBegin("StartRoleManagerService"); mSystemServiceManager.startService(new RoleManagerService( - mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext))); + mSystemContext, new LegacyRoleStateProviderImpl(mSystemContext))); t.traceEnd(); // We need to always start this service, regardless of whether the