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