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