1 /* 2 * Copyright (C) 2014 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 android.app; 18 19 import android.content.Context; 20 import android.os.Handler; 21 import android.os.Looper; 22 import android.os.Message; 23 import android.os.RemoteException; 24 import android.util.SparseArray; 25 import java.util.List; 26 27 /** 28 * Helper for monitoring the current importance of applications. 29 * @hide 30 */ 31 public class AppImportanceMonitor { 32 final Context mContext; 33 34 final SparseArray<AppEntry> mApps = new SparseArray<>(); 35 36 static class AppEntry { 37 final int uid; 38 final SparseArray<Integer> procs = new SparseArray<>(1); 39 int importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; 40 41 AppEntry(int _uid) { 42 uid = _uid; 43 } 44 } 45 46 final IProcessObserver mProcessObserver = new IProcessObserver.Stub() { 47 @Override 48 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { 49 } 50 51 @Override 52 public void onProcessStateChanged(int pid, int uid, int procState) { 53 synchronized (mApps) { 54 updateImportanceLocked(pid, uid, 55 ActivityManager.RunningAppProcessInfo.procStateToImportance(procState), 56 true); 57 } 58 } 59 60 @Override 61 public void onProcessDied(int pid, int uid) { 62 synchronized (mApps) { 63 updateImportanceLocked(pid, uid, 64 ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE, true); 65 } 66 } 67 }; 68 69 static final int MSG_UPDATE = 1; 70 71 final Handler mHandler; 72 73 public AppImportanceMonitor(Context context, Looper looper) { 74 mContext = context; 75 mHandler = new Handler(looper) { 76 @Override 77 public void handleMessage(Message msg) { 78 switch (msg.what) { 79 case MSG_UPDATE: 80 onImportanceChanged(msg.arg1, msg.arg2&0xffff, msg.arg2>>16); 81 break; 82 default: 83 super.handleMessage(msg); 84 } 85 } 86 }; 87 ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); 88 try { 89 ActivityManagerNative.getDefault().registerProcessObserver(mProcessObserver); 90 } catch (RemoteException e) { 91 } 92 List<ActivityManager.RunningAppProcessInfo> apps = am.getRunningAppProcesses(); 93 if (apps != null) { 94 for (int i=0; i<apps.size(); i++) { 95 ActivityManager.RunningAppProcessInfo app = apps.get(i); 96 updateImportanceLocked(app.uid, app.pid, app.importance, false); 97 } 98 } 99 } 100 101 public int getImportance(int uid) { 102 AppEntry ent = mApps.get(uid); 103 if (ent == null) { 104 return ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; 105 } 106 return ent.importance; 107 } 108 109 /** 110 * Report when an app's importance changed. Called on looper given to constructor. 111 */ 112 public void onImportanceChanged(int uid, int importance, int oldImportance) { 113 } 114 115 void updateImportanceLocked(int uid, int pid, int importance, boolean repChange) { 116 AppEntry ent = mApps.get(uid); 117 if (ent == null) { 118 ent = new AppEntry(uid); 119 mApps.put(uid, ent); 120 } 121 if (importance >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE) { 122 ent.procs.remove(pid); 123 } else { 124 ent.procs.put(pid, importance); 125 } 126 updateImportanceLocked(ent, repChange); 127 } 128 129 void updateImportanceLocked(AppEntry ent, boolean repChange) { 130 int appImp = ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; 131 for (int i=0; i<ent.procs.size(); i++) { 132 int procImp = ent.procs.valueAt(i); 133 if (procImp < appImp) { 134 appImp = procImp; 135 } 136 } 137 if (appImp != ent.importance) { 138 int impCode = appImp | (ent.importance<<16); 139 ent.importance = appImp; 140 if (appImp >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE) { 141 mApps.remove(ent.uid); 142 } 143 if (repChange) { 144 mHandler.obtainMessage(MSG_UPDATE, ent.uid, impCode).sendToTarget(); 145 } 146 } 147 } 148 } 149