blob: 067a50f9708aa3de0053cceafc1dbbad01d67976 [file] [log] [blame]
Daniel Sandlerb9eb2862013-06-14 20:17:30 -04001/*
2 * Copyright (C) 2013 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 com.android.launcher3;
18
19import android.app.ActivityManager;
20import android.app.Service;
21import android.content.Context;
22import android.content.Intent;
Daniel Sandlerb9eb2862013-06-14 20:17:30 -040023import android.os.*;
24import android.util.Log;
25import android.util.LongSparseArray;
26
27import java.util.ArrayList;
Daniel Sandler0adfc5a2013-07-07 17:16:49 -050028import java.util.List;
Daniel Sandlerb9eb2862013-06-14 20:17:30 -040029
30public class MemoryTracker extends Service {
31 public static final String TAG = MemoryTracker.class.getSimpleName();
32 public static final String ACTION_START_TRACKING = "com.android.launcher3.action.START_TRACKING";
33
34 private static final long UPDATE_RATE = 5000;
35
36 private static final int MSG_START = 1;
37 private static final int MSG_STOP = 2;
38 private static final int MSG_UPDATE = 3;
39
40 public static class ProcessMemInfo {
41 public int pid;
42 public String name;
Daniel Sandler8540bb82013-06-26 01:39:02 -040043 public long startTime;
Daniel Sandlerb9eb2862013-06-14 20:17:30 -040044 public long currentPss, currentUss;
45 public long[] pss = new long[256];
46 public long[] uss = new long[256];
47 //= new Meminfo[(int) (30 * 60 / (UPDATE_RATE / 1000))]; // 30 minutes
48 public long max = 1;
49 public int head = 0;
Daniel Sandler0adfc5a2013-07-07 17:16:49 -050050 public ProcessMemInfo(int pid, String name, long start) {
Daniel Sandlerb9eb2862013-06-14 20:17:30 -040051 this.pid = pid;
52 this.name = name;
Daniel Sandler0adfc5a2013-07-07 17:16:49 -050053 this.startTime = start;
Daniel Sandler8540bb82013-06-26 01:39:02 -040054 }
55 public long getUptime() {
56 return System.currentTimeMillis() - startTime;
Daniel Sandlerb9eb2862013-06-14 20:17:30 -040057 }
58 };
59 public final LongSparseArray<ProcessMemInfo> mData = new LongSparseArray<ProcessMemInfo>();
60 public final ArrayList<Long> mPids = new ArrayList<Long>();
61 private int[] mPidsArray = new int[0];
Daniel Sandler2566b572013-07-02 14:17:31 -050062 private final Object mLock = new Object();
Daniel Sandlerb9eb2862013-06-14 20:17:30 -040063
64 Handler mHandler = new Handler() {
65 @Override
66 public void handleMessage(Message m) {
67 switch (m.what) {
68 case MSG_START:
69 mHandler.removeMessages(MSG_UPDATE);
70 mHandler.sendEmptyMessage(MSG_UPDATE);
71 break;
72 case MSG_STOP:
73 mHandler.removeMessages(MSG_UPDATE);
74 break;
75 case MSG_UPDATE:
76 update();
77 mHandler.removeMessages(MSG_UPDATE);
78 mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE);
79 break;
80 }
81 }
82 };
83
84 ActivityManager mAm;
85
Daniel Sandler8540bb82013-06-26 01:39:02 -040086 public static void startTrackingMe(Context context, String name) {
87 context.startService(new Intent(context, MemoryTracker.class)
88 .setAction(MemoryTracker.ACTION_START_TRACKING)
89 .putExtra("pid", android.os.Process.myPid())
90 .putExtra("name", name)
91 );
92 }
93
Daniel Sandlerb9eb2862013-06-14 20:17:30 -040094 public ProcessMemInfo getMemInfo(int pid) {
95 return mData.get(pid);
96 }
97
98 public int[] getTrackedProcesses() {
99 return mPidsArray;
100 }
101
Daniel Sandler0adfc5a2013-07-07 17:16:49 -0500102 public void startTrackingProcess(int pid, String name, long start) {
Daniel Sandler2566b572013-07-02 14:17:31 -0500103 synchronized (mLock) {
Sunny Goyal70660032015-05-14 00:07:08 -0700104 final Long lpid = Long.valueOf(pid);
Daniel Sandler8540bb82013-06-26 01:39:02 -0400105
Daniel Sandler2566b572013-07-02 14:17:31 -0500106 if (mPids.contains(lpid)) return;
Daniel Sandler8540bb82013-06-26 01:39:02 -0400107
Daniel Sandler2566b572013-07-02 14:17:31 -0500108 mPids.add(lpid);
Daniel Sandler074e9ac2013-07-18 09:51:30 -0400109 updatePidsArrayL();
110
Daniel Sandler0adfc5a2013-07-07 17:16:49 -0500111 mData.put(pid, new ProcessMemInfo(pid, name, start));
Daniel Sandlerb9eb2862013-06-14 20:17:30 -0400112 }
Daniel Sandlerb9eb2862013-06-14 20:17:30 -0400113 }
114
Daniel Sandler074e9ac2013-07-18 09:51:30 -0400115 void updatePidsArrayL() {
116 final int N = mPids.size();
117 mPidsArray = new int[N];
118 StringBuffer sb = new StringBuffer("Now tracking processes: ");
119 for (int i=0; i<N; i++) {
120 final int p = mPids.get(i).intValue();
121 mPidsArray[i] = p;
122 sb.append(p); sb.append(" ");
123 }
124 Log.v(TAG, sb.toString());
125 }
126
Daniel Sandlerb9eb2862013-06-14 20:17:30 -0400127 void update() {
Daniel Sandler2566b572013-07-02 14:17:31 -0500128 synchronized (mLock) {
129 Debug.MemoryInfo[] dinfos = mAm.getProcessMemoryInfo(mPidsArray);
130 for (int i=0; i<dinfos.length; i++) {
131 Debug.MemoryInfo dinfo = dinfos[i];
Daniel Sandler074e9ac2013-07-18 09:51:30 -0400132 if (i > mPids.size()) {
133 Log.e(TAG, "update: unknown process info received: " + dinfo);
134 break;
135 }
Daniel Sandler2566b572013-07-02 14:17:31 -0500136 final long pid = mPids.get(i).intValue();
137 final ProcessMemInfo info = mData.get(pid);
138 info.head = (info.head+1) % info.pss.length;
139 info.pss[info.head] = info.currentPss = dinfo.getTotalPss();
140 info.uss[info.head] = info.currentUss = dinfo.getTotalPrivateDirty();
141 if (info.currentPss > info.max) info.max = info.currentPss;
142 if (info.currentUss > info.max) info.max = info.currentUss;
143 // Log.v(TAG, "update: pid " + pid + " pss=" + info.currentPss + " uss=" + info.currentUss);
144 if (info.currentPss == 0) {
145 Log.v(TAG, "update: pid " + pid + " has pss=0, it probably died");
146 mData.remove(pid);
147 }
148 }
149 for (int i=mPids.size()-1; i>=0; i--) {
150 final long pid = mPids.get(i).intValue();
151 if (mData.get(pid) == null) {
152 mPids.remove(i);
Daniel Sandler074e9ac2013-07-18 09:51:30 -0400153 updatePidsArrayL();
Daniel Sandler2566b572013-07-02 14:17:31 -0500154 }
Daniel Sandler0becf1f2013-06-27 22:39:26 -0400155 }
156 }
Daniel Sandlerb9eb2862013-06-14 20:17:30 -0400157 }
158
159 @Override
160 public void onCreate() {
161 mAm = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Daniel Sandler0adfc5a2013-07-07 17:16:49 -0500162
163 // catch up in case we crashed but other processes are still running
164 List<ActivityManager.RunningServiceInfo> svcs = mAm.getRunningServices(256);
165 for (ActivityManager.RunningServiceInfo svc : svcs) {
166 if (svc.service.getPackageName().equals(getPackageName())) {
Daniel Sandler074e9ac2013-07-18 09:51:30 -0400167 Log.v(TAG, "discovered running service: " + svc.process + " (" + svc.pid + ")");
168 startTrackingProcess(svc.pid, svc.process,
169 System.currentTimeMillis() - (SystemClock.elapsedRealtime() - svc.activeSince));
Daniel Sandler0adfc5a2013-07-07 17:16:49 -0500170 }
171 }
172
173 List<ActivityManager.RunningAppProcessInfo> procs = mAm.getRunningAppProcesses();
174 for (ActivityManager.RunningAppProcessInfo proc : procs) {
175 final String pname = proc.processName;
176 if (pname.startsWith(getPackageName())) {
Daniel Sandler074e9ac2013-07-18 09:51:30 -0400177 Log.v(TAG, "discovered other running process: " + pname + " (" + proc.pid + ")");
Daniel Sandler0adfc5a2013-07-07 17:16:49 -0500178 startTrackingProcess(proc.pid, pname, System.currentTimeMillis());
179 }
180 }
Daniel Sandlerb9eb2862013-06-14 20:17:30 -0400181 }
182
183 @Override
184 public void onDestroy() {
185 mHandler.sendEmptyMessage(MSG_STOP);
186 }
187
188 @Override
189 public int onStartCommand(Intent intent, int flags, int startId) {
Daniel Sandler074e9ac2013-07-18 09:51:30 -0400190 Log.v(TAG, "Received start id " + startId + ": " + intent);
Daniel Sandlerb9eb2862013-06-14 20:17:30 -0400191
Daniel Sandler49883402013-06-25 13:20:23 -0400192 if (intent != null) {
193 if (ACTION_START_TRACKING.equals(intent.getAction())) {
194 final int pid = intent.getIntExtra("pid", -1);
195 final String name = intent.getStringExtra("name");
Daniel Sandler0adfc5a2013-07-07 17:16:49 -0500196 final long start = intent.getLongExtra("start", System.currentTimeMillis());
197 startTrackingProcess(pid, name, start);
Daniel Sandler49883402013-06-25 13:20:23 -0400198 }
Daniel Sandlerb9eb2862013-06-14 20:17:30 -0400199 }
200
201 mHandler.sendEmptyMessage(MSG_START);
202
203 return START_STICKY;
204 }
205
206 public class MemoryTrackerInterface extends Binder {
207 MemoryTracker getService() {
208 return MemoryTracker.this;
209 }
210 }
211
212 private final IBinder mBinder = new MemoryTrackerInterface();
213
214 public IBinder onBind(Intent intent) {
215 mHandler.sendEmptyMessage(MSG_START);
216
217 return mBinder;
218 }
219}