• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 com.android.server.wm;
18 
19 import android.util.ArrayMap;
20 
21 import com.android.internal.annotations.GuardedBy;
22 import com.android.internal.os.BackgroundThread;
23 
24 import java.io.PrintWriter;
25 import java.util.concurrent.Executor;
26 import java.util.function.Predicate;
27 
28 /**
29  * A quick lookup for all processes with visible activities. It also tracks the CPU usage of
30  * host process with foreground (resumed) activity.
31  */
32 class VisibleActivityProcessTracker {
33     @GuardedBy("mProcMap")
34     private final ArrayMap<WindowProcessController, CpuTimeRecord> mProcMap = new ArrayMap<>();
35     final Executor mBgExecutor = BackgroundThread.getExecutor();
36     final ActivityTaskManagerService mAtms;
37 
VisibleActivityProcessTracker(ActivityTaskManagerService atms)38     VisibleActivityProcessTracker(ActivityTaskManagerService atms) {
39         mAtms = atms;
40     }
41 
42     /** Called when any activity is visible in the process that didn't have one. */
onAnyActivityVisible(WindowProcessController wpc)43     void onAnyActivityVisible(WindowProcessController wpc) {
44         final CpuTimeRecord r = new CpuTimeRecord(wpc);
45         synchronized (mProcMap) {
46             mProcMap.put(wpc, r);
47         }
48         if (wpc.hasResumedActivity()) {
49             r.mShouldGetCpuTime = true;
50             mBgExecutor.execute(r);
51         }
52     }
53 
54     /** Called when all visible activities of the process are no longer visible. */
onAllActivitiesInvisible(WindowProcessController wpc)55     void onAllActivitiesInvisible(WindowProcessController wpc) {
56         final CpuTimeRecord r = removeProcess(wpc);
57         if (r != null && r.mShouldGetCpuTime) {
58             mBgExecutor.execute(r);
59         }
60     }
61 
62     /** Called when an activity is resumed on a process which is known to have visible activity. */
onActivityResumedWhileVisible(WindowProcessController wpc)63     void onActivityResumedWhileVisible(WindowProcessController wpc) {
64         final CpuTimeRecord r;
65         synchronized (mProcMap) {
66             r = mProcMap.get(wpc);
67         }
68         if (r != null && !r.mShouldGetCpuTime) {
69             r.mShouldGetCpuTime = true;
70             mBgExecutor.execute(r);
71         }
72     }
73 
hasResumedActivity(int uid)74     boolean hasResumedActivity(int uid) {
75         return match(uid, WindowProcessController::hasResumedActivity);
76     }
77 
78     /**
79      * Returns {@code true} if the uid has a process that contains an activity with
80      * {@link ActivityRecord#mVisibleRequested} or {@link ActivityRecord#isVisible()} is true.
81      */
hasVisibleActivity(int uid)82     boolean hasVisibleActivity(int uid) {
83         return match(uid, null /* predicate */);
84     }
85 
match(int uid, Predicate<WindowProcessController> predicate)86     private boolean match(int uid, Predicate<WindowProcessController> predicate) {
87         synchronized (mProcMap) {
88             for (int i = mProcMap.size() - 1; i >= 0; i--) {
89                 final WindowProcessController wpc = mProcMap.keyAt(i);
90                 if (wpc.mUid == uid && (predicate == null || predicate.test(wpc))) {
91                     return true;
92                 }
93             }
94         }
95         return false;
96     }
97 
removeProcess(WindowProcessController wpc)98     CpuTimeRecord removeProcess(WindowProcessController wpc) {
99         synchronized (mProcMap) {
100             return mProcMap.remove(wpc);
101         }
102     }
103 
dump(PrintWriter pw, String prefix)104     void dump(PrintWriter pw, String prefix) {
105         pw.print(prefix + "VisibleActivityProcess:[");
106         synchronized (mProcMap) {
107             for (int i = mProcMap.size() - 1; i >= 0; i--) {
108                 pw.print(" " + mProcMap.keyAt(i));
109             }
110         }
111         pw.println("]");
112     }
113 
114     /**
115      * Get CPU time in background thread because it will access proc files or the lock of cpu
116      * tracker is held by a background thread.
117      */
118     private class CpuTimeRecord implements Runnable {
119         private final WindowProcessController mProc;
120         private long mCpuTime;
121         private boolean mHasStartCpuTime;
122         boolean mShouldGetCpuTime;
123 
CpuTimeRecord(WindowProcessController wpc)124         CpuTimeRecord(WindowProcessController wpc) {
125             mProc = wpc;
126         }
127 
128         @Override
run()129         public void run() {
130             if (mProc.getPid() == 0) {
131                 // The process is dead.
132                 return;
133             }
134             if (!mHasStartCpuTime) {
135                 mHasStartCpuTime = true;
136                 mCpuTime = mProc.getCpuTime();
137             } else {
138                 final long diff = mProc.getCpuTime() - mCpuTime;
139                 if (diff > 0) {
140                     mAtms.mAmInternal.updateForegroundTimeIfOnBattery(
141                             mProc.mInfo.packageName, mProc.mInfo.uid, diff);
142                 }
143             }
144         }
145     }
146 }
147