1 /*
2  * Copyright (C) 2024 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 package com.android.server.pm;
17 
18 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
19 import static android.content.pm.PackageManager.MATCH_ALL;
20 import static android.os.Process.INVALID_UID;
21 
22 import android.app.ActivityManager;
23 import android.app.ActivityManagerInternal;
24 import android.app.IActivityManager;
25 import android.app.IUidObserver;
26 import android.app.UidObserver;
27 import android.os.Process;
28 import android.os.RemoteException;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.concurrent.CountDownLatch;
33 import java.util.concurrent.TimeUnit;
34 
35 /**
36  * Use to monitor UIDs are really killed by the {@link IUidObserver}
37  */
38 final class KillAppBlocker {
39     private static final int MAX_WAIT_TIMEOUT_MS = 1000;
40     private CountDownLatch mUidsGoneCountDownLatch = new CountDownLatch(1);
41     private List mActiveUids = new ArrayList();
42     private boolean mRegistered = false;
43 
44     private final IUidObserver mUidObserver = new UidObserver() {
45         @Override
46         public void onUidGone(int uid, boolean disabled) {
47             synchronized (this) {
48                 mActiveUids.remove((Integer) uid);
49 
50                 if (mActiveUids.size() == 0) {
51                     mUidsGoneCountDownLatch.countDown();
52                 }
53             }
54         }
55     };
56 
register()57     void register() {
58         if (!mRegistered) {
59             IActivityManager am = ActivityManager.getService();
60             if (am != null) {
61                 try {
62                     am.registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_GONE,
63                             ActivityManager.PROCESS_STATE_UNKNOWN, "pm");
64                     mRegistered = true;
65                 } catch (RemoteException e) {
66                     // no-op
67                 }
68             }
69         }
70     }
71 
unregister()72     void unregister() {
73         if (mRegistered) {
74             IActivityManager am = ActivityManager.getService();
75             if (am != null) {
76                 try {
77                     mRegistered = false;
78                     am.unregisterUidObserver(mUidObserver);
79                 } catch (RemoteException e) {
80                     // no-op
81                 }
82             }
83         }
84     }
85 
waitAppProcessGone(ActivityManagerInternal ami, Computer snapshot, UserManagerService userManager, String packageName)86     void waitAppProcessGone(ActivityManagerInternal ami, Computer snapshot,
87             UserManagerService userManager, String packageName) {
88         if (!mRegistered) {
89             return;
90         }
91         synchronized (this) {
92             if (ami != null) {
93                 int[] users = userManager.getUserIds();
94 
95                 for (int i = 0; i < users.length; i++) {
96                     final int userId = users[i];
97                     final int uid = snapshot.getPackageUidInternal(
98                             packageName, MATCH_ALL, userId, Process.SYSTEM_UID);
99                     if (uid != INVALID_UID) {
100                         if (ami.getUidProcessState(uid) != PROCESS_STATE_NONEXISTENT) {
101                             mActiveUids.add(uid);
102                         }
103                     }
104                 }
105             }
106             if (mActiveUids.size() == 0) {
107                 // no active uid
108                 return;
109             }
110         }
111 
112         try {
113             mUidsGoneCountDownLatch.await(MAX_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
114         } catch (InterruptedException e) {
115             // no-op
116         }
117     }
118 }
119