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