blob: e0d0d8d7777841a4e5b2f28e4823b510edfc7a68 [file] [log] [blame]
Dianne Hackbornfee756f2014-07-16 17:31:10 -07001/*
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
17package android.app;
18
19import android.content.Context;
20import android.os.Handler;
21import android.os.Looper;
22import android.os.Message;
23import android.os.RemoteException;
24import android.util.SparseArray;
Dianne Hackbornfee756f2014-07-16 17:31:10 -070025import java.util.List;
26
27/**
28 * Helper for monitoring the current importance of applications.
29 * @hide
30 */
31public 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}