Merge "Use a single interface for reading pre-Q and pre-S role state."
This commit is contained in:
committed by
Android (Google) Code Review
commit
45a6e0e825
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user