ForegroundUtils.java revision c4ff3393f54403064b237349277cbf65f3277285
16142a54baae3289f734947c6b5375b12eb0fb722Chris Banes/* 26142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Copyright (C) 2014 The Android Open Source Project 36142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 46142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 56142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * you may not use this file except in compliance with the License. 66142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * You may obtain a copy of the License at 76142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 86142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 96142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 106142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Unless required by applicable law or agreed to in writing, software 116142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 126142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * See the License for the specific language governing permissions and 146142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * limitations under the License. 156142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 166142a54baae3289f734947c6b5375b12eb0fb722Chris Banespackage com.android.nfc; 176142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 186142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport java.util.ArrayList; 196142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport java.util.List; 206142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 216142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.app.ActivityManagerNative; 226142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.app.IActivityManager; 23c9b31694a631e135b85b2cf36a8e455e196a68e2Chris Banesimport android.app.IProcessObserver; 246142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.os.RemoteException; 256142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.util.Log; 266142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.util.SparseArray; 276142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.util.SparseBooleanArray; 286142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 296142a54baae3289f734947c6b5375b12eb0fb722Chris Banespublic class ForegroundUtils extends IProcessObserver.Stub { 306142a54baae3289f734947c6b5375b12eb0fb722Chris Banes static final boolean DBG = false; 316142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private final String TAG = "ForegroundUtils"; 326142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private final IActivityManager mIActivityManager; 336142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 346142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private final Object mLock = new Object(); 356142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // We need to keep track of the individual PIDs per UID, 366142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // since a single UID may have multiple processes running 376142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // that transition into foreground/background state. 386142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private final SparseArray<SparseBooleanArray> mForegroundUidPids = 396142a54baae3289f734947c6b5375b12eb0fb722Chris Banes new SparseArray<SparseBooleanArray>(); 406142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private final SparseArray<List<Callback>> mBackgroundCallbacks = 416142a54baae3289f734947c6b5375b12eb0fb722Chris Banes new SparseArray<List<Callback>>(); 426142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 436142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private static class Singleton { 446142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private static final ForegroundUtils INSTANCE = new ForegroundUtils(); 456142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 466142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 476142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private ForegroundUtils() { 486142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mIActivityManager = ActivityManagerNative.getDefault(); 496142a54baae3289f734947c6b5375b12eb0fb722Chris Banes try { 506142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mIActivityManager.registerProcessObserver(this); 516142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } catch (RemoteException e) { 526142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // Should not happen! 536142a54baae3289f734947c6b5375b12eb0fb722Chris Banes Log.e(TAG, "ForegroundUtils: could not get IActivityManager"); 546142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 556142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 566142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 576142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public interface Callback { 586142a54baae3289f734947c6b5375b12eb0fb722Chris Banes void onUidToBackground(int uid); 596142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 606142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 616142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public static ForegroundUtils getInstance() { 626142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return Singleton.INSTANCE; 636142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 646142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 656142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 666142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Checks whether the specified UID has any activities running in the foreground, 676142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * and if it does, registers a callback for when that UID no longer has any foreground 686142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * activities. This is done atomically, so callers can be ensured that they will 696142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * get a callback if this method returns true. 706142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 716142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @param callback Callback to be called 726142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @param uid The UID to be checked 736142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @return true when the UID has an Activity in the foreground and the callback 746142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * , false otherwise 756142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 766142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public boolean registerUidToBackgroundCallback(Callback callback, int uid) { 776142a54baae3289f734947c6b5375b12eb0fb722Chris Banes synchronized (mLock) { 786142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (!isInForegroundLocked(uid)) { 796142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return false; 806142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 816142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // This uid is in the foreground; register callback for when it moves 826142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // into the background. 836142a54baae3289f734947c6b5375b12eb0fb722Chris Banes List<Callback> callbacks = mBackgroundCallbacks.get(uid, new ArrayList<Callback>()); 846142a54baae3289f734947c6b5375b12eb0fb722Chris Banes callbacks.add(callback); 856142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mBackgroundCallbacks.put(uid, callbacks); 866142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return true; 876142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 886142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 896142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 906142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 916142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @param uid The UID to be checked 926142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @return whether the UID has any activities running in the foreground 936142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 946142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public boolean isInForeground(int uid) { 956142a54baae3289f734947c6b5375b12eb0fb722Chris Banes synchronized (mLock) { 966142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return isInForegroundLocked(uid); 976142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 986142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 996142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 1006142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 1016142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @return a list of UIDs currently in the foreground, or an empty list 1026142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * if none are found. 1036142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 1046142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public List<Integer> getForegroundUids() { 1056142a54baae3289f734947c6b5375b12eb0fb722Chris Banes ArrayList<Integer> uids = new ArrayList<Integer>(mForegroundUidPids.size()); 1066142a54baae3289f734947c6b5375b12eb0fb722Chris Banes synchronized (mLock) { 1076142a54baae3289f734947c6b5375b12eb0fb722Chris Banes for (int i = 0; i < mForegroundUidPids.size(); i++) { 1086142a54baae3289f734947c6b5375b12eb0fb722Chris Banes uids.add(mForegroundUidPids.keyAt(i)); 1096142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1106142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1116142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return uids; 1126142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1136142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 1146142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private boolean isInForegroundLocked(int uid) { 1156142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return mForegroundUidPids.get(uid) != null; 1166142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1176142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 1186142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private void handleUidToBackground(int uid) { 1196142a54baae3289f734947c6b5375b12eb0fb722Chris Banes ArrayList<Callback> pendingCallbacks = null; 1206142a54baae3289f734947c6b5375b12eb0fb722Chris Banes synchronized (mLock) { 1216142a54baae3289f734947c6b5375b12eb0fb722Chris Banes List<Callback> callbacks = mBackgroundCallbacks.get(uid); 1226142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (callbacks != null) { 1236142a54baae3289f734947c6b5375b12eb0fb722Chris Banes pendingCallbacks = new ArrayList<Callback>(callbacks); 1246142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // Only call them once 1256142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mBackgroundCallbacks.remove(uid); 1266142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 127c9b31694a631e135b85b2cf36a8e455e196a68e2Chris Banes } 128c9b31694a631e135b85b2cf36a8e455e196a68e2Chris Banes // Release lock for callbacks 129c9b31694a631e135b85b2cf36a8e455e196a68e2Chris Banes if (pendingCallbacks != null) { 130c9b31694a631e135b85b2cf36a8e455e196a68e2Chris Banes for (Callback callback : pendingCallbacks) { 1316142a54baae3289f734947c6b5375b12eb0fb722Chris Banes callback.onUidToBackground(uid); 1326142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1336142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1346142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1356142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 1366142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @Override 1376142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void onForegroundActivitiesChanged(int pid, int uid, 1386142a54baae3289f734947c6b5375b12eb0fb722Chris Banes boolean hasForegroundActivities) throws RemoteException { 1396142a54baae3289f734947c6b5375b12eb0fb722Chris Banes boolean uidToBackground = false; 1406142a54baae3289f734947c6b5375b12eb0fb722Chris Banes synchronized (mLock) { 1416142a54baae3289f734947c6b5375b12eb0fb722Chris Banes SparseBooleanArray foregroundPids = mForegroundUidPids.get(uid, 1426142a54baae3289f734947c6b5375b12eb0fb722Chris Banes new SparseBooleanArray()); 1436142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (hasForegroundActivities) { 1446142a54baae3289f734947c6b5375b12eb0fb722Chris Banes foregroundPids.put(pid, true); 1456142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } else { 1466142a54baae3289f734947c6b5375b12eb0fb722Chris Banes foregroundPids.delete(pid); 1476142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1486142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (foregroundPids.size() == 0) { 1496142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mForegroundUidPids.remove(uid); 1506142a54baae3289f734947c6b5375b12eb0fb722Chris Banes uidToBackground = true; 1516142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } else { 1526142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mForegroundUidPids.put(uid, foregroundPids); 1536142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1546142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1556142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (uidToBackground) { 1566142a54baae3289f734947c6b5375b12eb0fb722Chris Banes handleUidToBackground(uid); 1576142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1586142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (DBG) { 1596142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (DBG) Log.d(TAG, "Foreground changed, PID: " + Integer.toString(pid) + " UID: " + 1606142a54baae3289f734947c6b5375b12eb0fb722Chris Banes Integer.toString(uid) + " foreground: " + 1616142a54baae3289f734947c6b5375b12eb0fb722Chris Banes hasForegroundActivities); 1626142a54baae3289f734947c6b5375b12eb0fb722Chris Banes synchronized (mLock) { 1636142a54baae3289f734947c6b5375b12eb0fb722Chris Banes Log.d(TAG, "Foreground UID/PID combinations:"); 1646142a54baae3289f734947c6b5375b12eb0fb722Chris Banes for (int i = 0; i < mForegroundUidPids.size(); i++) { 1656142a54baae3289f734947c6b5375b12eb0fb722Chris Banes int foregroundUid = mForegroundUidPids.keyAt(i); 1666142a54baae3289f734947c6b5375b12eb0fb722Chris Banes SparseBooleanArray foregroundPids = mForegroundUidPids.get(foregroundUid); 1676142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (foregroundPids.size() == 0) { 1686142a54baae3289f734947c6b5375b12eb0fb722Chris Banes Log.e(TAG, "No PIDS associated with foreground UID!"); 1696142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1706142a54baae3289f734947c6b5375b12eb0fb722Chris Banes for (int j = 0; j < foregroundPids.size(); j++) 1716142a54baae3289f734947c6b5375b12eb0fb722Chris Banes Log.d(TAG, "UID: " + Integer.toString(foregroundUid) + " PID: " + 1726142a54baae3289f734947c6b5375b12eb0fb722Chris Banes Integer.toString(foregroundPids.keyAt(j))); 1736142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1746142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1756142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1766142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1776142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 1786142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 1796142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @Override 1806142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void onProcessDied(int pid, int uid) throws RemoteException { 1816142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (DBG) Log.d(TAG, "Process died; UID " + Integer.toString(uid) + " PID " + 1826142a54baae3289f734947c6b5375b12eb0fb722Chris Banes Integer.toString(pid)); 1836142a54baae3289f734947c6b5375b12eb0fb722Chris Banes onForegroundActivitiesChanged(pid, uid, false); 1846142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1856142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 1866142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @Override 1876142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void onProcessStateChanged(int pid, int uid, int procState) 188d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes throws RemoteException { 189d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes // Don't care 190d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes } 191d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes} 192d6e47228c44aaadb0d4518da6db5c3f5dffda1abChris Banes