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
This commit is contained in:
Hai Zhang
2021-01-13 02:21:10 -08:00
parent ce6238e031
commit ce2a80437d
6 changed files with 329 additions and 326 deletions

View File

@@ -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<String> 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);
}
}

View File

@@ -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<String, Set<String>> getLegacyRoleState(@UserIdInt int userId) {
Map<String, Set<String>> roles = readFile(userId);
if (roles == null) {
roles = readFromLegacySettings(userId);
}
return roles;
}
@Nullable
private Map<String, Set<String>> readFile(@UserIdInt int userId) {
File file = getFile(userId);
try (FileInputStream in = new AtomicFile(file).openRead()) {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, null);
Map<String, Set<String>> 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<String, Set<String>> 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<String, Set<String>> parseRoles(@NonNull XmlPullParser parser) throws IOException,
XmlPullParserException {
Map<String, Set<String>> 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<String> roleHolders = parseRoleHoldersLocked(parser);
roles.put(roleName, roleHolders);
}
}
return roles;
}
@NonNull
private Set<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
throws IOException, XmlPullParserException {
Set<String> 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<String, Set<String>> readFromLegacySettings(@UserIdInt int userId) {
Map<String, Set<String>> 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);
}
}

View File

@@ -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.
* <p>
* 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.
* <p>
* 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<String> getLegacyRoleHolders(@NonNull String roleName, @UserIdInt int userId);
Map<String, Set<String>> getLegacyRoleState(@UserIdInt int userId);
}

View File

@@ -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<Void> 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<String> 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;

View File

@@ -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<String, Set<String>> 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<String, Set<String>> entry : roles.getRoles().entrySet()) {
for (Map.Entry<String, Set<String>> entry : roles.entrySet()) {
String roleName = entry.getKey();
ArraySet<String> 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<String> roleHolders = parseRoleHoldersLocked(parser);
mRoles.put(roleName, roleHolders);
}
}
}
@NonNull
private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
throws IOException, XmlPullParserException {
ArraySet<String> 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.
*/

View File

@@ -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