• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.car;
17 
18 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
19 
20 import android.car.builtin.app.ActivityManagerHelper;
21 import android.car.builtin.app.ActivityManagerHelper.ProcessObserverCallback;
22 import android.car.builtin.util.Slogf;
23 import android.content.Context;
24 import android.os.Handler;
25 import android.os.HandlerThread;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.util.ArrayMap;
29 import android.util.ArraySet;
30 import android.util.Log;
31 
32 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
33 import com.android.car.internal.util.IndentingPrintWriter;
34 import com.android.internal.annotations.GuardedBy;
35 
36 import java.lang.ref.WeakReference;
37 import java.util.Arrays;
38 import java.util.Map;
39 import java.util.Set;
40 
41 /**
42  * Service to monitor AMS for new Activity or Service launching.
43  */
44 public class SystemActivityMonitoringService implements CarServiceBase {
45     private static final int INVALID_STACK_ID = -1;
46     private final Context mContext;
47     private final ProcessObserverCallback mProcessObserver = new ProcessObserver();
48 
49     private final HandlerThread mMonitorHandlerThread = CarServiceUtils.getHandlerThread(
50             getClass().getSimpleName());
51     private final ActivityMonitorHandler mHandler = new ActivityMonitorHandler(
52             mMonitorHandlerThread.getLooper(), this);
53 
54     private final Object mLock = new Object();
55 
56     @GuardedBy("mLock")
57     private final Map<Integer, Set<Integer>> mForegroundUidPids = new ArrayMap<>();
58 
SystemActivityMonitoringService(Context context)59     public SystemActivityMonitoringService(Context context) {
60         mContext = context;
61     }
62 
63     @Override
init()64     public void init() {
65         // Monitoring both listeners are necessary as there are cases where one listener cannot
66         // monitor activity change.
67         ActivityManagerHelper.registerProcessObserverCallback(mProcessObserver);
68     }
69 
70     @Override
release()71     public void release() {
72         ActivityManagerHelper.unregisterProcessObserverCallback(mProcessObserver);
73     }
74 
75     @Override
76     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)77     public void dump(IndentingPrintWriter writer) {
78         writer.println("*SystemActivityMonitoringService*");
79         writer.println(" Top Tasks per display:");
80         synchronized (mLock) {
81             writer.println(" Foreground uid-pids:");
82             for (Integer key : mForegroundUidPids.keySet()) {
83                 Set<Integer> pids = mForegroundUidPids.get(key);
84                 if (pids == null) {
85                     continue;
86                 }
87                 writer.println("uid:" + key + ", pids:" + Arrays.toString(pids.toArray()));
88             }
89         }
90     }
91 
isInForeground(int pid, int uid)92     public boolean isInForeground(int pid, int uid) {
93         synchronized (mLock) {
94             Set<Integer> pids = mForegroundUidPids.get(uid);
95             if (pids == null) {
96                 return false;
97             }
98             if (pids.contains(pid)) {
99                 return true;
100             }
101         }
102         return false;
103     }
104 
handleForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities)105     private void handleForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
106         synchronized (mLock) {
107             if (foregroundActivities) {
108                 Set<Integer> pids = mForegroundUidPids.get(uid);
109                 if (pids == null) {
110                     pids = new ArraySet<Integer>();
111                     mForegroundUidPids.put(uid, pids);
112                 }
113                 pids.add(pid);
114             } else {
115                 doHandlePidGoneLocked(pid, uid);
116             }
117         }
118     }
119 
handleProcessDied(int pid, int uid)120     private void handleProcessDied(int pid, int uid) {
121         synchronized (mLock) {
122             doHandlePidGoneLocked(pid, uid);
123         }
124     }
125 
126     @GuardedBy("mLock")
doHandlePidGoneLocked(int pid, int uid)127     private void doHandlePidGoneLocked(int pid, int uid) {
128         Set<Integer> pids = mForegroundUidPids.get(uid);
129         if (pids != null) {
130             pids.remove(pid);
131             if (pids.isEmpty()) {
132                 mForegroundUidPids.remove(uid);
133             }
134         }
135     }
136 
137     private class ProcessObserver extends ProcessObserverCallback {
138         @Override
onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities)139         public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
140             if (Slogf.isLoggable(CarLog.TAG_AM, Log.INFO)) {
141                 Slogf.i(CarLog.TAG_AM,
142                         String.format("onForegroundActivitiesChanged uid %d pid %d fg %b",
143                                 uid, pid, foregroundActivities));
144             }
145             mHandler.requestForegroundActivitiesChanged(pid, uid, foregroundActivities);
146         }
147 
148         @Override
onProcessDied(int pid, int uid)149         public void onProcessDied(int pid, int uid) {
150             mHandler.requestProcessDied(pid, uid);
151         }
152     }
153 
154     private static final class ActivityMonitorHandler extends Handler {
155         private static final String TAG = ActivityMonitorHandler.class.getSimpleName();
156 
157         private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 1;
158         private static final int MSG_PROCESS_DIED = 2;
159 
160         private final WeakReference<SystemActivityMonitoringService> mService;
161 
ActivityMonitorHandler(Looper looper, SystemActivityMonitoringService service)162         private ActivityMonitorHandler(Looper looper, SystemActivityMonitoringService service) {
163             super(looper);
164             mService = new WeakReference<SystemActivityMonitoringService>(service);
165         }
166 
requestForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities)167         private void requestForegroundActivitiesChanged(int pid, int uid,
168                 boolean foregroundActivities) {
169             Message msg = obtainMessage(MSG_FOREGROUND_ACTIVITIES_CHANGED, pid, uid,
170                     Boolean.valueOf(foregroundActivities));
171             sendMessage(msg);
172         }
173 
requestProcessDied(int pid, int uid)174         private void requestProcessDied(int pid, int uid) {
175             Message msg = obtainMessage(MSG_PROCESS_DIED, pid, uid);
176             sendMessage(msg);
177         }
178 
179         @Override
handleMessage(Message msg)180         public void handleMessage(Message msg) {
181             SystemActivityMonitoringService service = mService.get();
182             if (service == null) {
183                 Slogf.i(TAG, "handleMessage null service");
184                 return;
185             }
186             switch (msg.what) {
187                 case MSG_FOREGROUND_ACTIVITIES_CHANGED:
188                     service.handleForegroundActivitiesChanged(msg.arg1, msg.arg2,
189                             (Boolean) msg.obj);
190                     break;
191                 case MSG_PROCESS_DIED:
192                     service.handleProcessDied(msg.arg1, msg.arg2);
193                     break;
194             }
195         }
196     }
197 }
198