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.content.pm.PackageManagerInternal.PackageListObserver;
21 import android.util.ArraySet;
22 
23 import com.android.internal.annotations.GuardedBy;
24 
25 class PackageObserverHelper {
26 
27     @NonNull
28     private final Object mLock = new Object();
29 
30     // True set of observers, immutable, used to iterate without blocking the lock, since
31     // callbacks can take a long time to return. The previous alternative used a bunch of
32     // list copies on each notify call, which is suboptimal in cases of few mutations and
33     // lots of notifications.
34     @NonNull
35     @GuardedBy("mLock")
36     private ArraySet<PackageListObserver> mActiveSnapshot = new ArraySet<>();
37 
addObserver(@onNull PackageListObserver observer)38     public void addObserver(@NonNull PackageListObserver observer) {
39         synchronized (mLock) {
40             ArraySet<PackageListObserver> set = new ArraySet<>(mActiveSnapshot);
41             set.add(observer);
42             mActiveSnapshot = set;
43         }
44     }
45 
removeObserver(@onNull PackageListObserver observer)46     public void removeObserver(@NonNull PackageListObserver observer) {
47         synchronized (mLock) {
48             ArraySet<PackageListObserver> set = new ArraySet<>(mActiveSnapshot);
49             set.remove(observer);
50             mActiveSnapshot = set;
51         }
52     }
53 
notifyAdded(@onNull String packageName, int uid)54     public void notifyAdded(@NonNull String packageName, int uid) {
55         ArraySet<PackageListObserver> observers;
56         synchronized (mLock) {
57             observers = mActiveSnapshot;
58         }
59         final int size = observers.size();
60         for (int index = 0; index < size; index++) {
61             observers.valueAt(index).onPackageAdded(packageName, uid);
62         }
63     }
64 
notifyChanged(@onNull String packageName, int uid)65     public void notifyChanged(@NonNull String packageName, int uid) {
66         ArraySet<PackageListObserver> observers;
67         synchronized (mLock) {
68             observers = mActiveSnapshot;
69         }
70         final int size = observers.size();
71         for (int index = 0; index < size; index++) {
72             observers.valueAt(index).onPackageChanged(packageName, uid);
73         }
74     }
75 
notifyRemoved(@onNull String packageName, int uid)76     public void notifyRemoved(@NonNull String packageName, int uid) {
77         ArraySet<PackageListObserver> observers;
78         synchronized (mLock) {
79             observers = mActiveSnapshot;
80         }
81         final int size = observers.size();
82         for (int index = 0; index < size; index++) {
83             observers.valueAt(index).onPackageRemoved(packageName, uid);
84         }
85     }
86 }
87