1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.infra;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UserIdInt;
22 import android.content.ComponentName;
23 import android.util.ArraySet;
24 import android.util.SparseArray;
25 
26 import com.android.internal.annotations.GuardedBy;
27 
28 import java.io.PrintWriter;
29 import java.util.List;
30 
31 /**
32  * Helper class used to manage a {@link WhitelistHelper} per user instance when the main service
33  * cannot hold a lock when external entities (typically {@code ActivityManagerService}) needs to
34  * get whitelist info.
35  *
36  * <p>This class is thread safe.
37  */
38 // TODO: add unit tests
39 public class GlobalWhitelistState {
40 
41     // Uses full-name to avoid collision with service-provided mLock
42     protected final Object mGlobalWhitelistStateLock = new Object();
43 
44     // TODO: should not be exposed directly
45     @Nullable
46     @GuardedBy("mGlobalWhitelistStateLock")
47     protected SparseArray<WhitelistHelper> mWhitelisterHelpers;
48 
49     /**
50      * Sets the whitelist for the given user.
51      */
setWhitelist(@serIdInt int userId, @Nullable List<String> packageNames, @Nullable List<ComponentName> components)52     public void setWhitelist(@UserIdInt int userId, @Nullable List<String> packageNames,
53             @Nullable List<ComponentName> components) {
54         synchronized (mGlobalWhitelistStateLock) {
55             if (mWhitelisterHelpers == null) {
56                 mWhitelisterHelpers = new SparseArray<>(1);
57             }
58             WhitelistHelper helper = mWhitelisterHelpers.get(userId);
59             if (helper == null) {
60                 helper = new WhitelistHelper();
61                 mWhitelisterHelpers.put(userId, helper);
62             }
63             helper.setWhitelist(packageNames, components);
64         }
65     }
66 
67     /**
68      * Checks if the given package is whitelisted for the given user.
69      */
isWhitelisted(@serIdInt int userId, @NonNull String packageName)70     public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) {
71         synchronized (mGlobalWhitelistStateLock) {
72             if (mWhitelisterHelpers == null) return false;
73             final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
74             return helper == null ? false : helper.isWhitelisted(packageName);
75         }
76     }
77 
78     /**
79      * Checks if the given component is whitelisted for the given user.
80      */
isWhitelisted(@serIdInt int userId, @NonNull ComponentName componentName)81     public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) {
82         synchronized (mGlobalWhitelistStateLock) {
83             if (mWhitelisterHelpers == null) return false;
84             final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
85             return helper == null ? false : helper.isWhitelisted(componentName);
86         }
87     }
88 
89     /**
90      * Gets the whitelisted components for the given package and user.
91      */
getWhitelistedComponents(@serIdInt int userId, @NonNull String packageName)92     public ArraySet<ComponentName> getWhitelistedComponents(@UserIdInt int userId,
93             @NonNull String packageName) {
94         synchronized (mGlobalWhitelistStateLock) {
95             if (mWhitelisterHelpers == null) return null;
96             final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
97             return helper == null ? null : helper.getWhitelistedComponents(packageName);
98         }
99     }
100 
101     /**
102      * Resets the whitelist for the given user.
103      */
resetWhitelist(@onNull int userId)104     public void resetWhitelist(@NonNull int userId) {
105         synchronized (mGlobalWhitelistStateLock) {
106             if (mWhitelisterHelpers == null) return;
107             mWhitelisterHelpers.remove(userId);
108             if (mWhitelisterHelpers.size() == 0) {
109                 mWhitelisterHelpers = null;
110             }
111         }
112     }
113 
114     /**
115      * Dumps it!
116      */
dump(@onNull String prefix, @NonNull PrintWriter pw)117     public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
118         pw.print(prefix); pw.print("State: ");
119         synchronized (mGlobalWhitelistStateLock) {
120             if (mWhitelisterHelpers == null) {
121                 pw.println("empty");
122                 return;
123             }
124             pw.print(mWhitelisterHelpers.size()); pw.println(" services");
125             final String prefix2 = prefix + "  ";
126             for (int i = 0; i < mWhitelisterHelpers.size(); i++) {
127                 final int userId  = mWhitelisterHelpers.keyAt(i);
128                 final WhitelistHelper helper = mWhitelisterHelpers.valueAt(i);
129                 helper.dump(prefix2, "Whitelist for userId " + userId, pw);
130             }
131         }
132     }
133 }
134