Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4fa5f4e6 authored by Hai Zhang's avatar Hai Zhang
Browse files

Add getDefaultHolders() for SmsRoleBehavior.

This change adds getDefaultHolders() implementation for
SmsRoleBehavior, which reads the string array resource
android.R.array.config_defaultRoleHolders and parses its content.

Bug: 110557011
Bug: 122730135
Test: build
Change-Id: Iacaa3cf38b14585e64d44a661e869ee877c39a98
parent ea777821
Loading
Loading
Loading
Loading
+98 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2019 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.packageinstaller.role.model;

import android.content.Context;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;

import androidx.annotation.NonNull;

import java.util.Arrays;
import java.util.List;

/**
 * Provides access to all the default role holders.
 */
public class DefaultRoleHolders {

    private static final String LOG_TAG = DefaultRoleHolders.class.getSimpleName();

    @NonNull
    private static final Object sLock = new Object();

    private static ArrayMap<String, List<String>> sDefaultRoleHolders;

    /**
     * Get the default role holders.
     *
     * @param context the {@code Context} used to read the system resource
     *
     * @return a map from role name to a list of package names of the default holders
     */
    @NonNull
    public static ArrayMap<String, List<String>> get(@NonNull Context context) {
        synchronized (sLock) {
            if (sDefaultRoleHolders == null) {
                sDefaultRoleHolders = load(context);
            }
            return sDefaultRoleHolders;
        }
    }

    @NonNull
    private static ArrayMap<String, List<String>> load(@NonNull Context context) {
        ArrayMap<String, List<String>> defaultRoleHolders = new ArrayMap<>();
        String[] items = context.getResources().getStringArray(
                android.R.array.config_defaultRoleHolders);
        int itemsLength = items.length;
        for (int i = 0; i < itemsLength; i++) {
            String item = items[i];

            item = item.trim();
            String[] roleNameAndPackageNames = item.split("\\s*:\\s*", 2);
            if (roleNameAndPackageNames.length != 2) {
                Log.e(LOG_TAG, "Invalid item: " + item);
                continue;
            }
            String roleName = roleNameAndPackageNames[0];
            if (roleName.isEmpty()) {
                Log.e(LOG_TAG, "Empty role name: " + item);
                continue;
            }
            if (defaultRoleHolders.containsKey(roleName)) {
                Log.e(LOG_TAG, "Duplicate role name: " + roleName);
                continue;
            }
            String packageNamesString = roleNameAndPackageNames[1];
            if (packageNamesString.isEmpty()) {
                Log.e(LOG_TAG, "Empty package names: " + item);
                continue;
            }
            List<String> packageNames = Arrays.asList(packageNamesString.split("\\s*,\\s*"));
            ArraySet<String> uniquePackageNames = new ArraySet<>(packageNames);
            if (packageNames.size() != uniquePackageNames.size()) {
                Log.e(LOG_TAG, "Duplicate package names: " + packageNamesString);
                packageNames.clear();
                packageNames.addAll(uniquePackageNames);
            }
            defaultRoleHolders.put(roleName, packageNames);
        }
        return defaultRoleHolders;
    }
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -397,7 +397,7 @@ public class Role {
        otherRoleNames.remove(mName);
        otherRoleNames.remove(mName);


        List<String> permissionsToRevoke = new ArrayList<>(mPermissions);
        List<String> permissionsToRevoke = new ArrayList<>(mPermissions);
        ArrayMap<String, Role> roles = Roles.getRoles(context);
        ArrayMap<String, Role> roles = Roles.get(context);
        int otherRoleNamesSize = otherRoleNames.size();
        int otherRoleNamesSize = otherRoleNames.size();
        for (int i = 0; i < otherRoleNamesSize; i++) {
        for (int i = 0; i < otherRoleNamesSize; i++) {
            String roleName = otherRoleNames.get(i);
            String roleName = otherRoleNames.get(i);
+3 −3
Original line number Original line Diff line number Diff line
@@ -125,17 +125,17 @@ public class Roles {
     * @return a map from role name to {@link Role} instances
     * @return a map from role name to {@link Role} instances
     */
     */
    @NonNull
    @NonNull
    public static ArrayMap<String, Role> getRoles(@NonNull Context context) {
    public static ArrayMap<String, Role> get(@NonNull Context context) {
        synchronized (sLock) {
        synchronized (sLock) {
            if (sRoles == null) {
            if (sRoles == null) {
                sRoles = loadRoles(context);
                sRoles = load(context);
            }
            }
            return sRoles;
            return sRoles;
        }
        }
    }
    }


    @NonNull
    @NonNull
    private static ArrayMap<String, Role> loadRoles(@NonNull Context context) {
    private static ArrayMap<String, Role> load(@NonNull Context context) {
        // If the storage model feature flag is disabled, we need to fiddle
        // If the storage model feature flag is disabled, we need to fiddle
        // around with permission definitions to return us to pre-Q behavior.
        // around with permission definitions to return us to pre-Q behavior.
        // STOPSHIP(b/112545973): remove once feature enabled by default
        // STOPSHIP(b/112545973): remove once feature enabled by default
+11 −2
Original line number Original line Diff line number Diff line
@@ -65,9 +65,16 @@ public class SmsRoleBehavior implements RoleBehavior {


    @Nullable
    @Nullable
    private String getDefaultHolder(@NonNull Role role, @NonNull Context context) {
    private String getDefaultHolder(@NonNull Role role, @NonNull Context context) {
        // TODO: STOPSHIP: Read system resource for default handler.
        String defaultPackageName = CollectionUtils.firstOrNull(DefaultRoleHolders.get(context).get(
                role.getName()));
        if (defaultPackageName == null) {
            return null;
            return null;
        }
        }
        if (!role.isPackageQualified(defaultPackageName, context)) {
            return null;
        }
        return defaultPackageName;
    }


    @Nullable
    @Nullable
    @Override
    @Override
@@ -77,6 +84,8 @@ public class SmsRoleBehavior implements RoleBehavior {
            return defaultPackageName;
            return defaultPackageName;
        }
        }


        // TODO: STOPSHIP: This was the previous behavior, however this allows any third-party app
        // to suddenly become the default SMS app and get the permissions.
        List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser(
        List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser(
                Process.myUserHandle(), context);
                Process.myUserHandle(), context);
        return CollectionUtils.firstOrNull(qualifyingPackageNames);
        return CollectionUtils.firstOrNull(qualifyingPackageNames);
+10 −5
Original line number Original line Diff line number Diff line
@@ -47,6 +47,9 @@ public class RoleControllerServiceImpl extends RoleControllerService {


    private static final String LOG_TAG = RoleControllerServiceImpl.class.getSimpleName();
    private static final String LOG_TAG = RoleControllerServiceImpl.class.getSimpleName();


    // TODO: STOPSHIP: Turn off debugging before we ship.
    private static final boolean DEBUG = true;

    private RoleManager mRoleManager;
    private RoleManager mRoleManager;


    private HandlerThread mWorkerThread;
    private HandlerThread mWorkerThread;
@@ -136,10 +139,12 @@ public class RoleControllerServiceImpl extends RoleControllerService {


    @WorkerThread
    @WorkerThread
    private void grantDefaultRoles(@NonNull RoleManagerCallback callback) {
    private void grantDefaultRoles(@NonNull RoleManagerCallback callback) {
        if (DEBUG) {
            Log.i(LOG_TAG, "Granting default roles, user: " + UserHandle.myUserId());
            Log.i(LOG_TAG, "Granting default roles, user: " + UserHandle.myUserId());
        }


        // Gather the available roles for current user.
        // Gather the available roles for current user.
        ArrayMap<String, Role> roleMap = Roles.getRoles(this);
        ArrayMap<String, Role> roleMap = Roles.get(this);
        List<Role> roles = new ArrayList<>();
        List<Role> roles = new ArrayList<>();
        List<String> roleNames = new ArrayList<>();
        List<String> roleNames = new ArrayList<>();
        ArraySet<String> addedRoleNames = new ArraySet<>();
        ArraySet<String> addedRoleNames = new ArraySet<>();
@@ -248,7 +253,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {
    @WorkerThread
    @WorkerThread
    private void addRoleHolder(@NonNull String roleName, @NonNull String packageName,
    private void addRoleHolder(@NonNull String roleName, @NonNull String packageName,
            @NonNull RoleManagerCallback callback) {
            @NonNull RoleManagerCallback callback) {
        Role role = Roles.getRoles(this).get(roleName);
        Role role = Roles.get(this).get(roleName);
        if (role == null) {
        if (role == null) {
            Log.e(LOG_TAG, "Unknown role: " + roleName);
            Log.e(LOG_TAG, "Unknown role: " + roleName);
            callback.onFailure();
            callback.onFailure();
@@ -302,7 +307,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {
    @WorkerThread
    @WorkerThread
    private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName,
    private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName,
            @NonNull RoleManagerCallback callback) {
            @NonNull RoleManagerCallback callback) {
        Role role = Roles.getRoles(this).get(roleName);
        Role role = Roles.get(this).get(roleName);
        if (role == null) {
        if (role == null) {
            Log.e(LOG_TAG, "Unknown role: " + roleName);
            Log.e(LOG_TAG, "Unknown role: " + roleName);
            callback.onFailure();
            callback.onFailure();
@@ -332,7 +337,7 @@ public class RoleControllerServiceImpl extends RoleControllerService {


    @WorkerThread
    @WorkerThread
    private void clearRoleHolders(@NonNull String roleName, @NonNull RoleManagerCallback callback) {
    private void clearRoleHolders(@NonNull String roleName, @NonNull RoleManagerCallback callback) {
        Role role = Roles.getRoles(this).get(roleName);
        Role role = Roles.get(this).get(roleName);
        if (role == null) {
        if (role == null) {
            Log.e(LOG_TAG, "Unknown role: " + roleName);
            Log.e(LOG_TAG, "Unknown role: " + roleName);
            callback.onFailure();
            callback.onFailure();
Loading