1 /*
2  * Copyright (C) 2021 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.server.pm;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UserIdInt;
22 import android.util.ArrayMap;
23 import android.util.SparseArray;
24 
25 import com.android.internal.annotations.GuardedBy;
26 import com.android.internal.annotations.VisibleForTesting;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 /**
32  * Set of pending broadcasts for aggregating enable/disable of components.
33  */
34 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
35 public final class PendingPackageBroadcasts {
36 
37     private final Object mLock = new PackageManagerTracedLock();
38 
39     // for each user id, a map of <package name -> components within that package>
40     @GuardedBy("mLock")
41     final SparseArray<ArrayMap<String, ArrayList<String>>> mUidMap;
42 
PendingPackageBroadcasts()43     public PendingPackageBroadcasts() {
44         mUidMap = new SparseArray<>(2);
45     }
46 
hasPackage(@serIdInt int userId, @NonNull String packageName)47     public boolean hasPackage(@UserIdInt int userId, @NonNull String packageName) {
48         synchronized (mLock) {
49             final ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId);
50             return packages != null && packages.containsKey(packageName);
51         }
52     }
53 
put(int userId, String packageName, ArrayList<String> components)54     public void put(int userId, String packageName, ArrayList<String> components) {
55         synchronized (mLock) {
56             ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId);
57             packages.put(packageName, components);
58         }
59     }
60 
addComponent(@serIdInt int userId, @NonNull String packageName, @NonNull String componentClassName)61     public void addComponent(@UserIdInt int userId, @NonNull String packageName,
62             @NonNull String componentClassName) {
63         synchronized (mLock) {
64             ArrayList<String> components = getOrAllocate(userId, packageName);
65             if (!components.contains(componentClassName)) {
66                 components.add(componentClassName);
67             }
68         }
69     }
70 
addComponents(@serIdInt int userId, @NonNull String packageName, @NonNull List<String> componentClassNames)71     public void addComponents(@UserIdInt int userId, @NonNull String packageName,
72             @NonNull List<String> componentClassNames) {
73         synchronized (mLock) {
74             ArrayList<String> components = getOrAllocate(userId, packageName);
75             for (int index = 0; index < componentClassNames.size(); index++) {
76                 String componentClassName = componentClassNames.get(index);
77                 if (!components.contains(componentClassName)) {
78                     components.add(componentClassName);
79                 }
80             }
81         }
82     }
83 
remove(int userId, String packageName)84     public void remove(int userId, String packageName) {
85         synchronized (mLock) {
86             ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId);
87             if (packages != null) {
88                 packages.remove(packageName);
89             }
90         }
91     }
92 
remove(int userId)93     public void remove(int userId) {
94         synchronized (mLock) {
95             mUidMap.remove(userId);
96         }
97     }
98 
99     @Nullable
copiedMap()100     public SparseArray<ArrayMap<String, ArrayList<String>>> copiedMap() {
101         synchronized (mLock) {
102             SparseArray<ArrayMap<String, ArrayList<String>>> copy = new SparseArray<>();
103             for (int userIdIndex = 0; userIdIndex < mUidMap.size(); userIdIndex++) {
104                 final ArrayMap<String, ArrayList<String>> packages = mUidMap.valueAt(userIdIndex);
105                 ArrayMap<String, ArrayList<String>> packagesCopy = new ArrayMap<>();
106                 for (int packagesIndex = 0; packagesIndex < packages.size(); packagesIndex++) {
107                     packagesCopy.put(packages.keyAt(packagesIndex),
108                             new ArrayList<>(packages.valueAt(packagesIndex)));
109                 }
110                 copy.put(mUidMap.keyAt(userIdIndex), packagesCopy);
111             }
112             return copy;
113         }
114     }
115 
clear()116     public void clear() {
117         synchronized (mLock) {
118             mUidMap.clear();
119         }
120     }
121 
getOrAllocate(int userId)122     private ArrayMap<String, ArrayList<String>> getOrAllocate(int userId) {
123         synchronized (mLock) {
124             ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId);
125             if (map == null) {
126                 map = new ArrayMap<>();
127                 mUidMap.put(userId, map);
128             }
129             return map;
130         }
131     }
132 
getOrAllocate(int userId, @NonNull String packageName)133     private ArrayList<String> getOrAllocate(int userId, @NonNull String packageName) {
134         synchronized (mLock) {
135             ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId);
136             if (map == null) {
137                 map = new ArrayMap<>();
138                 mUidMap.put(userId, map);
139             }
140 
141             return map.computeIfAbsent(packageName, k -> new ArrayList<>());
142         }
143     }
144 }
145