blob: f82dc24f3d617ec3619930935c8d697f723dd9d0 [file] [log] [blame]
Bookatz94726412017-08-31 09:26:15 -07001/*
2 * Copyright (C) 2017 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 */
16package com.android.server.stats;
17
Chenjie Yu05013b32017-11-21 10:21:41 -080018import android.annotation.Nullable;
Bookatz94726412017-08-31 09:26:15 -070019import android.app.AlarmManager;
20import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
David Chende701692017-10-05 13:16:02 -070024import android.content.IntentFilter;
25import android.content.pm.PackageInfo;
26import android.content.pm.PackageManager;
27import android.content.pm.UserInfo;
David Chenc8a43242017-10-17 16:23:28 -070028import android.net.NetworkStats;
Chenjie Yu05013b32017-11-21 10:21:41 -080029import android.net.wifi.IWifiManager;
30import android.net.wifi.WifiActivityEnergyInfo;
David Chenc8a43242017-10-17 16:23:28 -070031import android.os.BatteryStatsInternal;
Bookatz94726412017-08-31 09:26:15 -070032import android.os.Binder;
David Chende701692017-10-05 13:16:02 -070033import android.os.Bundle;
Chenjie Yu937d7422018-01-10 16:37:53 -080034import android.os.Environment;
Bookatzb487b552017-09-18 11:26:01 -070035import android.os.IBinder;
Bookatz94726412017-08-31 09:26:15 -070036import android.os.IStatsCompanionService;
37import android.os.IStatsManager;
Chenjie Yu05013b32017-11-21 10:21:41 -080038import android.os.Parcelable;
Bookatz94726412017-08-31 09:26:15 -070039import android.os.Process;
Bookatz1b0b1142017-09-08 11:58:42 -070040import android.os.RemoteException;
Bookatz94726412017-08-31 09:26:15 -070041import android.os.ServiceManager;
Chenjie Yu937d7422018-01-10 16:37:53 -080042import android.os.StatFs;
David Chen1481fe12017-10-16 13:16:34 -070043import android.os.StatsLogEventWrapper;
Chenjie Yu05013b32017-11-21 10:21:41 -080044import android.os.SynchronousResultReceiver;
Chenjie Yu937d7422018-01-10 16:37:53 -080045import android.os.SystemClock;
David Chende701692017-10-05 13:16:02 -070046import android.os.UserHandle;
47import android.os.UserManager;
Chenjie Yu937d7422018-01-10 16:37:53 -080048import android.telephony.ModemActivityInfo;
49import android.telephony.TelephonyManager;
Bookatz94726412017-08-31 09:26:15 -070050import android.util.Slog;
David Chenc8a43242017-10-17 16:23:28 -070051import android.util.StatsLog;
52
53import com.android.internal.annotations.GuardedBy;
54import com.android.internal.net.NetworkStatsFactory;
Chenjie Yu937d7422018-01-10 16:37:53 -080055import com.android.internal.os.KernelCpuSpeedReader;
David Chenc8a43242017-10-17 16:23:28 -070056import com.android.internal.os.KernelWakelockReader;
57import com.android.internal.os.KernelWakelockStats;
Chenjie Yu7f8def92017-11-03 09:33:15 -070058import com.android.internal.os.PowerProfile;
David Chenc8a43242017-10-17 16:23:28 -070059import com.android.server.LocalServices;
60import com.android.server.SystemService;
Bookatz94726412017-08-31 09:26:15 -070061
David Chende701692017-10-05 13:16:02 -070062import java.util.ArrayList;
63import java.util.List;
Bookatzc68a9d22017-09-27 14:09:55 -070064import java.util.Map;
Chenjie Yu05013b32017-11-21 10:21:41 -080065import java.util.concurrent.TimeoutException;
Bookatzc68a9d22017-09-27 14:09:55 -070066
Bookatz94726412017-08-31 09:26:15 -070067/**
68 * Helper service for statsd (the native stats management service in cmds/statsd/).
69 * Used for registering and receiving alarms on behalf of statsd.
David Chen1481fe12017-10-16 13:16:34 -070070 *
Bookatz6bc51d72017-09-28 16:43:40 -070071 * @hide
Bookatz94726412017-08-31 09:26:15 -070072 */
73public class StatsCompanionService extends IStatsCompanionService.Stub {
Chenjie Yu05013b32017-11-21 10:21:41 -080074 /**
75 * How long to wait on an individual subsystem to return its stats.
76 */
77 private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000;
78
79 public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
80
Bookatz94726412017-08-31 09:26:15 -070081 static final String TAG = "StatsCompanionService";
82 static final boolean DEBUG = true;
David Chenadaf8b32017-11-03 15:42:08 -070083 public static final String ACTION_TRIGGER_COLLECTION =
84 "com.android.server.stats.action.TRIGGER_COLLECTION";
Bookatz94726412017-08-31 09:26:15 -070085
86 private final Context mContext;
87 private final AlarmManager mAlarmManager;
Bookatzb487b552017-09-18 11:26:01 -070088 @GuardedBy("sStatsdLock")
Bookatz1b0b1142017-09-08 11:58:42 -070089 private static IStatsManager sStatsd;
Bookatzb487b552017-09-18 11:26:01 -070090 private static final Object sStatsdLock = new Object();
Bookatz94726412017-08-31 09:26:15 -070091
92 private final PendingIntent mAnomalyAlarmIntent;
Chenjie Yub3dda412017-10-24 13:41:59 -070093 private final PendingIntent mPullingAlarmIntent;
David Chende701692017-10-05 13:16:02 -070094 private final BroadcastReceiver mAppUpdateReceiver;
David Chen47e8f4d2017-10-11 15:34:13 -070095 private final BroadcastReceiver mUserUpdateReceiver;
yro947fbce2017-11-15 22:50:23 -080096 private final ShutdownEventReceiver mShutdownEventReceiver;
Chenjie Yu7f8def92017-11-03 09:33:15 -070097 private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
98 private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
99 private final KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
Chenjie Yu05013b32017-11-21 10:21:41 -0800100 private IWifiManager mWifiManager = null;
101 private TelephonyManager mTelephony = null;
Chenjie Yu937d7422018-01-10 16:37:53 -0800102 private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
103 private final StatFs mStatFsSystem =
104 new StatFs(Environment.getRootDirectory().getAbsolutePath());
105 private final StatFs mStatFsTemp =
106 new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
Bookatz94726412017-08-31 09:26:15 -0700107
Bookatz94726412017-08-31 09:26:15 -0700108 public StatsCompanionService(Context context) {
109 super();
110 mContext = context;
111 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
112
113 mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
114 new Intent(mContext, AnomalyAlarmReceiver.class), 0);
Chenjie Yub3dda412017-10-24 13:41:59 -0700115 mPullingAlarmIntent = PendingIntent.getBroadcast(
116 mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
David Chende701692017-10-05 13:16:02 -0700117 mAppUpdateReceiver = new AppUpdateReceiver();
David Chen47e8f4d2017-10-11 15:34:13 -0700118 mUserUpdateReceiver = new BroadcastReceiver() {
119 @Override
120 public void onReceive(Context context, Intent intent) {
121 synchronized (sStatsdLock) {
122 sStatsd = fetchStatsdService();
123 if (sStatsd == null) {
124 Slog.w(TAG, "Could not access statsd");
125 return;
126 }
127 try {
128 // Pull the latest state of UID->app name, version mapping.
129 // Needed since the new user basically has a version of every app.
130 informAllUidsLocked(context);
131 } catch (RemoteException e) {
David Chen1481fe12017-10-16 13:16:34 -0700132 Slog.e(TAG, "Failed to inform statsd latest update of all apps", e);
David Chen47e8f4d2017-10-11 15:34:13 -0700133 forgetEverything();
134 }
135 }
136 }
137 };
yro947fbce2017-11-15 22:50:23 -0800138 mShutdownEventReceiver = new ShutdownEventReceiver();
David Chende701692017-10-05 13:16:02 -0700139 Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED.");
Chenjie Yu7f8def92017-11-03 09:33:15 -0700140 PowerProfile powerProfile = new PowerProfile(context);
141 final int numClusters = powerProfile.getNumCpuClusters();
142 mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
143 int firstCpuOfCluster = 0;
144 for (int i = 0; i < numClusters; i++) {
145 final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i);
146 mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
147 numSpeedSteps);
148 firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i);
149 }
Bookatz94726412017-08-31 09:26:15 -0700150 }
151
David Chenadaf8b32017-11-03 15:42:08 -0700152 @Override
153 public void sendBroadcast(String pkg, String cls) {
154 mContext.sendBroadcastAsUser(new Intent(ACTION_TRIGGER_COLLECTION).setClassName(pkg, cls),
155 UserHandle.SYSTEM);
156 }
157
David Chen1481fe12017-10-16 13:16:34 -0700158 private final static int[] toIntArray(List<Integer> list) {
David Chende701692017-10-05 13:16:02 -0700159 int[] ret = new int[list.size()];
David Chen1481fe12017-10-16 13:16:34 -0700160 for (int i = 0; i < ret.length; i++) {
David Chende701692017-10-05 13:16:02 -0700161 ret[i] = list.get(i);
162 }
163 return ret;
164 }
165
Dianne Hackborn3accca02013-09-20 09:32:11 -0700166 private final static long[] toLongArray(List<Long> list) {
167 long[] ret = new long[list.size()];
168 for (int i = 0; i < ret.length; i++) {
169 ret[i] = list.get(i);
170 }
171 return ret;
172 }
173
David Chende701692017-10-05 13:16:02 -0700174 // Assumes that sStatsdLock is held.
175 private final void informAllUidsLocked(Context context) throws RemoteException {
176 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
177 PackageManager pm = context.getPackageManager();
178 final List<UserInfo> users = um.getUsers(true);
179 if (DEBUG) {
David Chen1481fe12017-10-16 13:16:34 -0700180 Slog.w(TAG, "Iterating over " + users.size() + " profiles.");
David Chende701692017-10-05 13:16:02 -0700181 }
182
183 List<Integer> uids = new ArrayList();
Dianne Hackborn3accca02013-09-20 09:32:11 -0700184 List<Long> versions = new ArrayList();
David Chende701692017-10-05 13:16:02 -0700185 List<String> apps = new ArrayList();
186
187 // Add in all the apps for every user/profile.
188 for (UserInfo profile : users) {
David Chen1481fe12017-10-16 13:16:34 -0700189 List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id);
190 for (int j = 0; j < pi.size(); j++) {
191 if (pi.get(j).applicationInfo != null) {
192 uids.add(pi.get(j).applicationInfo.uid);
Dianne Hackborn3accca02013-09-20 09:32:11 -0700193 versions.add(pi.get(j).getLongVersionCode());
David Chen1481fe12017-10-16 13:16:34 -0700194 apps.add(pi.get(j).packageName);
195 }
196 }
David Chende701692017-10-05 13:16:02 -0700197 }
Dianne Hackborn3accca02013-09-20 09:32:11 -0700198 sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new
David Chen1481fe12017-10-16 13:16:34 -0700199 String[apps.size()]));
David Chende701692017-10-05 13:16:02 -0700200 if (DEBUG) {
David Chen1481fe12017-10-16 13:16:34 -0700201 Slog.w(TAG, "Sent data for " + uids.size() + " apps");
David Chende701692017-10-05 13:16:02 -0700202 }
203 }
204
David Chen1481fe12017-10-16 13:16:34 -0700205 public final static class AppUpdateReceiver extends BroadcastReceiver {
David Chende701692017-10-05 13:16:02 -0700206 @Override
207 public void onReceive(Context context, Intent intent) {
David Chen47e8f4d2017-10-11 15:34:13 -0700208 /**
209 * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid
210 * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag.
David Chend6896892017-10-25 11:49:03 -0700211 * If we can't find the value for EXTRA_REPLACING, we default to false.
David Chen47e8f4d2017-10-11 15:34:13 -0700212 */
David Chend6896892017-10-25 11:49:03 -0700213 if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)
214 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
David Chen47e8f4d2017-10-11 15:34:13 -0700215 return; // Keep only replacing or normal add and remove.
216 }
David Chend6896892017-10-25 11:49:03 -0700217 Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
David Chende701692017-10-05 13:16:02 -0700218 synchronized (sStatsdLock) {
219 if (sStatsd == null) {
yrof6d1ca52017-11-15 15:38:34 -0800220 Slog.w(TAG, "Could not access statsd to inform it of an app update");
David Chende701692017-10-05 13:16:02 -0700221 return;
222 }
223 try {
224 if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
225 Bundle b = intent.getExtras();
226 int uid = b.getInt(Intent.EXTRA_UID);
227 boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
228 if (!replacing) {
229 // Don't bother sending an update if we're right about to get another
230 // intent for the new version that's added.
231 PackageManager pm = context.getPackageManager();
232 String app = intent.getData().getSchemeSpecificPart();
233 sStatsd.informOnePackageRemoved(app, uid);
234 }
235 } else {
236 PackageManager pm = context.getPackageManager();
237 Bundle b = intent.getExtras();
238 int uid = b.getInt(Intent.EXTRA_UID);
239 String app = intent.getData().getSchemeSpecificPart();
240 PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER);
Dianne Hackborn3accca02013-09-20 09:32:11 -0700241 sStatsd.informOnePackage(app, uid, pi.getLongVersionCode());
David Chende701692017-10-05 13:16:02 -0700242 }
243 } catch (Exception e) {
244 Slog.w(TAG, "Failed to inform statsd of an app update", e);
245 }
246 }
247 }
David Chen1481fe12017-10-16 13:16:34 -0700248 }
David Chende701692017-10-05 13:16:02 -0700249
David Chen1481fe12017-10-16 13:16:34 -0700250 public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
Bookatz94726412017-08-31 09:26:15 -0700251 @Override
Bookatzb487b552017-09-18 11:26:01 -0700252 public void onReceive(Context context, Intent intent) {
253 Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred.");
254 synchronized (sStatsdLock) {
255 if (sStatsd == null) {
256 Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
257 return;
258 }
259 try {
260 // Two-way call to statsd to retain AlarmManager wakelock
261 sStatsd.informAnomalyAlarmFired();
262 } catch (RemoteException e) {
263 Slog.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
264 }
Bookatz94726412017-08-31 09:26:15 -0700265 }
Bookatzb487b552017-09-18 11:26:01 -0700266 // AlarmManager releases its own wakelock here.
Bookatz94726412017-08-31 09:26:15 -0700267 }
David Chen1481fe12017-10-16 13:16:34 -0700268 }
Bookatzb487b552017-09-18 11:26:01 -0700269
Chenjie Yub3dda412017-10-24 13:41:59 -0700270 public final static class PullingAlarmReceiver extends BroadcastReceiver {
271 @Override
272 public void onReceive(Context context, Intent intent) {
273 if (DEBUG)
274 Slog.d(TAG, "Time to poll something.");
275 synchronized (sStatsdLock) {
276 if (sStatsd == null) {
yro947fbce2017-11-15 22:50:23 -0800277 Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
Chenjie Yub3dda412017-10-24 13:41:59 -0700278 return;
279 }
280 try {
281 // Two-way call to statsd to retain AlarmManager wakelock
282 sStatsd.informPollAlarmFired();
283 } catch (RemoteException e) {
yro947fbce2017-11-15 22:50:23 -0800284 Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
Chenjie Yub3dda412017-10-24 13:41:59 -0700285 }
Bookatzb487b552017-09-18 11:26:01 -0700286 }
Chenjie Yub3dda412017-10-24 13:41:59 -0700287 // AlarmManager releases its own wakelock here.
288 }
David Chen1481fe12017-10-16 13:16:34 -0700289 }
Bookatz94726412017-08-31 09:26:15 -0700290
yro947fbce2017-11-15 22:50:23 -0800291 public final static class ShutdownEventReceiver extends BroadcastReceiver {
292 @Override
293 public void onReceive(Context context, Intent intent) {
294 /**
295 * Skip immediately if intent is not relevant to device shutdown.
296 */
297 if (!intent.getAction().equals(Intent.ACTION_REBOOT)
298 && !intent.getAction().equals(Intent.ACTION_SHUTDOWN)) {
299 return;
300 }
301 Slog.i(TAG, "StatsCompanionService noticed a shutdown.");
302 synchronized (sStatsdLock) {
303 if (sStatsd == null) {
304 Slog.w(TAG, "Could not access statsd to inform it of a shutdown event.");
305 return;
306 }
307 try {
308 sStatsd.writeDataToDisk();
309 } catch (Exception e) {
310 Slog.w(TAG, "Failed to inform statsd of a shutdown event.", e);
311 }
312 }
313 }
314 }
315
Bookatz94726412017-08-31 09:26:15 -0700316 @Override // Binder call
317 public void setAnomalyAlarm(long timestampMs) {
318 enforceCallingPermission();
319 if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
320 final long callingToken = Binder.clearCallingIdentity();
321 try {
322 // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
323 // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
324 // AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm.
325 mAlarmManager.set(AlarmManager.RTC, timestampMs, mAnomalyAlarmIntent);
326 } finally {
327 Binder.restoreCallingIdentity(callingToken);
328 }
329 }
330
331 @Override // Binder call
332 public void cancelAnomalyAlarm() {
333 enforceCallingPermission();
334 if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
335 final long callingToken = Binder.clearCallingIdentity();
336 try {
337 mAlarmManager.cancel(mAnomalyAlarmIntent);
338 } finally {
339 Binder.restoreCallingIdentity(callingToken);
340 }
341 }
342
343 @Override // Binder call
Chenjie Yub3dda412017-10-24 13:41:59 -0700344 public void setPullingAlarms(long timestampMs, long intervalMs) {
345 enforceCallingPermission();
346 if (DEBUG)
347 Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
348 final long callingToken = Binder.clearCallingIdentity();
349 try {
350 // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
351 // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
352 // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
353 mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
354 } finally {
355 Binder.restoreCallingIdentity(callingToken);
356 }
Bookatz94726412017-08-31 09:26:15 -0700357 }
358
359 @Override // Binder call
Chenjie Yub3dda412017-10-24 13:41:59 -0700360 public void cancelPullingAlarms() {
361 enforceCallingPermission();
362 if (DEBUG)
363 Slog.d(TAG, "Cancelling pulling alarm");
364 final long callingToken = Binder.clearCallingIdentity();
365 try {
366 mAlarmManager.cancel(mPullingAlarmIntent);
367 } finally {
368 Binder.restoreCallingIdentity(callingToken);
369 }
Bookatz94726412017-08-31 09:26:15 -0700370 }
371
David Chenc8a43242017-10-17 16:23:28 -0700372 private StatsLogEventWrapper[] addNetworkStats(int tag, NetworkStats stats, boolean withFGBG) {
373 List<StatsLogEventWrapper> ret = new ArrayList<>();
374 int size = stats.size();
375 NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
376 for (int j = 0; j < size; j++) {
377 stats.getValues(j, entry);
378 StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5);
379 e.writeInt(entry.uid);
380 if (withFGBG) {
381 e.writeInt(entry.set);
382 }
383 e.writeLong(entry.rxBytes);
384 e.writeLong(entry.rxPackets);
385 e.writeLong(entry.txBytes);
386 e.writeLong(entry.txPackets);
387 ret.add(e);
388 }
389 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
390 }
391
392 /**
393 * Allows rollups per UID but keeping the set (foreground/background) slicing.
394 * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java
395 */
396 private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) {
397 final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1);
398
399 final NetworkStats.Entry entry = new NetworkStats.Entry();
400 entry.iface = NetworkStats.IFACE_ALL;
401 entry.tag = NetworkStats.TAG_NONE;
402 entry.metered = NetworkStats.METERED_ALL;
403 entry.roaming = NetworkStats.ROAMING_ALL;
404
405 int size = stats.size();
406 NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values
407 for (int i = 0; i < size; i++) {
408 stats.getValues(i, recycle);
409
410 // Skip specific tags, since already counted in TAG_NONE
411 if (recycle.tag != NetworkStats.TAG_NONE) continue;
412
413 entry.set = recycle.set; // Allows slicing by background/foreground
414 entry.uid = recycle.uid;
415 entry.rxBytes = recycle.rxBytes;
416 entry.rxPackets = recycle.rxPackets;
417 entry.txBytes = recycle.txBytes;
418 entry.txPackets = recycle.txPackets;
419 // Operations purposefully omitted since we don't use them for statsd.
420 ret.combineValues(entry);
421 }
422 return ret;
423 }
424
Chenjie Yu05013b32017-11-21 10:21:41 -0800425 /**
426 * Helper method to extract the Parcelable controller info from a
427 * SynchronousResultReceiver.
428 */
429 private static <T extends Parcelable> T awaitControllerInfo(
430 @Nullable SynchronousResultReceiver receiver) {
431 if (receiver == null) {
432 return null;
433 }
434
435 try {
436 final SynchronousResultReceiver.Result result =
437 receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS);
438 if (result.bundle != null) {
439 // This is the final destination for the Bundle.
440 result.bundle.setDefusable(true);
441
442 final T data = result.bundle.getParcelable(
443 RESULT_RECEIVER_CONTROLLER_KEY);
444 if (data != null) {
445 return data;
446 }
447 }
448 Slog.e(TAG, "no controller energy info supplied for " + receiver.getName());
449 } catch (TimeoutException e) {
450 Slog.w(TAG, "timeout reading " + receiver.getName() + " stats");
451 }
452 return null;
453 }
454
455 /**
456 *
457 * Pulls wifi controller activity energy info from WiFiManager
458 */
Bookatzc68a9d22017-09-27 14:09:55 -0700459 @Override // Binder call
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700460 public StatsLogEventWrapper[] pullData(int tagId) {
Bookatzc68a9d22017-09-27 14:09:55 -0700461 enforceCallingPermission();
David Chenc8a43242017-10-17 16:23:28 -0700462 if (DEBUG)
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700463 Slog.d(TAG, "Pulling " + tagId);
Bookatzc68a9d22017-09-27 14:09:55 -0700464
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700465 switch (tagId) {
Chenjie Yu31d14d72017-12-12 17:54:33 -0800466 case StatsLog.WIFI_BYTES_TRANSFER: {
David Chenc8a43242017-10-17 16:23:28 -0700467 long token = Binder.clearCallingIdentity();
468 try {
469 // TODO: Consider caching the following call to get BatteryStatsInternal.
470 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
471 String[] ifaces = bs.getWifiIfaces();
472 if (ifaces.length == 0) {
473 return null;
474 }
475 NetworkStatsFactory nsf = new NetworkStatsFactory();
476 // Combine all the metrics per Uid into one record.
477 NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
478 NetworkStats.TAG_NONE, null).groupedByUid();
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700479 return addNetworkStats(tagId, stats, false);
David Chenc8a43242017-10-17 16:23:28 -0700480 } catch (java.io.IOException e) {
481 Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
482 } finally {
483 Binder.restoreCallingIdentity(token);
484 }
485 break;
486 }
Chenjie Yu31d14d72017-12-12 17:54:33 -0800487 case StatsLog.MOBILE_BYTES_TRANSFER: {
David Chenc8a43242017-10-17 16:23:28 -0700488 long token = Binder.clearCallingIdentity();
489 try {
490 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
491 String[] ifaces = bs.getMobileIfaces();
492 if (ifaces.length == 0) {
493 return null;
494 }
495 NetworkStatsFactory nsf = new NetworkStatsFactory();
496 // Combine all the metrics per Uid into one record.
497 NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
498 NetworkStats.TAG_NONE, null).groupedByUid();
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700499 return addNetworkStats(tagId, stats, false);
David Chenc8a43242017-10-17 16:23:28 -0700500 } catch (java.io.IOException e) {
501 Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
502 } finally {
503 Binder.restoreCallingIdentity(token);
504 }
505 break;
506 }
Chenjie Yu31d14d72017-12-12 17:54:33 -0800507 case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
David Chenc8a43242017-10-17 16:23:28 -0700508 long token = Binder.clearCallingIdentity();
509 try {
510 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
511 String[] ifaces = bs.getWifiIfaces();
512 if (ifaces.length == 0) {
513 return null;
514 }
515 NetworkStatsFactory nsf = new NetworkStatsFactory();
516 NetworkStats stats = rollupNetworkStatsByFGBG(
517 nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
518 NetworkStats.TAG_NONE, null));
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700519 return addNetworkStats(tagId, stats, true);
David Chenc8a43242017-10-17 16:23:28 -0700520 } catch (java.io.IOException e) {
521 Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
522 } finally {
523 Binder.restoreCallingIdentity(token);
524 }
525 break;
526 }
Chenjie Yu31d14d72017-12-12 17:54:33 -0800527 case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
David Chenc8a43242017-10-17 16:23:28 -0700528 long token = Binder.clearCallingIdentity();
529 try {
530 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
531 String[] ifaces = bs.getMobileIfaces();
532 if (ifaces.length == 0) {
533 return null;
534 }
535 NetworkStatsFactory nsf = new NetworkStatsFactory();
536 NetworkStats stats = rollupNetworkStatsByFGBG(
537 nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
538 NetworkStats.TAG_NONE, null));
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700539 return addNetworkStats(tagId, stats, true);
David Chenc8a43242017-10-17 16:23:28 -0700540 } catch (java.io.IOException e) {
541 Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
542 } finally {
543 Binder.restoreCallingIdentity(token);
544 }
545 break;
546 }
Chenjie Yu31d14d72017-12-12 17:54:33 -0800547 case StatsLog.KERNEL_WAKELOCK: {
Bookatzc68a9d22017-09-27 14:09:55 -0700548 final KernelWakelockStats wakelockStats =
549 mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
David Chenc8a43242017-10-17 16:23:28 -0700550 List<StatsLogEventWrapper> ret = new ArrayList();
Bookatzc68a9d22017-09-27 14:09:55 -0700551 for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
552 String name = ent.getKey();
553 KernelWakelockStats.Entry kws = ent.getValue();
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700554 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4);
David Chenc8a43242017-10-17 16:23:28 -0700555 e.writeString(name);
David Chen1481fe12017-10-16 13:16:34 -0700556 e.writeInt(kws.mCount);
557 e.writeInt(kws.mVersion);
558 e.writeLong(kws.mTotalTime);
David Chen1481fe12017-10-16 13:16:34 -0700559 ret.add(e);
Bookatzc68a9d22017-09-27 14:09:55 -0700560 }
David Chenc8a43242017-10-17 16:23:28 -0700561 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
David Chen1481fe12017-10-16 13:16:34 -0700562 }
Chenjie Yu31d14d72017-12-12 17:54:33 -0800563 case StatsLog.CPU_TIME_PER_FREQ: {
Chenjie Yu7f8def92017-11-03 09:33:15 -0700564 List<StatsLogEventWrapper> ret = new ArrayList();
565 for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
Chenjie Yu1ee9b742018-01-10 16:02:57 -0800566 long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
Chenjie Yu7f8def92017-11-03 09:33:15 -0700567 if (clusterTimeMs != null) {
568 for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
569 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
Chenjie Yu937d7422018-01-10 16:37:53 -0800570 e.writeInt(cluster);
Chenjie Yu7f8def92017-11-03 09:33:15 -0700571 e.writeInt(speed);
572 e.writeLong(clusterTimeMs[speed]);
573 ret.add(e);
574 }
575 }
576 }
577 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
578 }
Chenjie Yu31d14d72017-12-12 17:54:33 -0800579 case StatsLog.WIFI_ACTIVITY_ENERGY_INFO: {
Chenjie Yu05013b32017-11-21 10:21:41 -0800580 List<StatsLogEventWrapper> ret = new ArrayList();
581 long token = Binder.clearCallingIdentity();
582 if (mWifiManager == null) {
583 mWifiManager = IWifiManager.Stub.asInterface(ServiceManager.getService(
584 Context.WIFI_SERVICE));
585 }
586 if (mWifiManager != null) {
587 try {
588 SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
589 mWifiManager.requestActivityInfo(wifiReceiver);
590 final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
591 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
592 e.writeLong(wifiInfo.getTimeStamp());
593 e.writeInt(wifiInfo.getStackState());
594 e.writeLong(wifiInfo.getControllerTxTimeMillis());
595 e.writeLong(wifiInfo.getControllerRxTimeMillis());
596 e.writeLong(wifiInfo.getControllerIdleTimeMillis());
597 e.writeLong(wifiInfo.getControllerEnergyUsed());
598 ret.add(e);
Chenjie Yu937d7422018-01-10 16:37:53 -0800599 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
Chenjie Yu05013b32017-11-21 10:21:41 -0800600 } catch (RemoteException e) {
601 Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e);
602 } finally {
603 Binder.restoreCallingIdentity(token);
604 }
605 }
606 break;
607 }
Chenjie Yu31d14d72017-12-12 17:54:33 -0800608 case StatsLog.MODEM_ACTIVITY_INFO: {
Chenjie Yu05013b32017-11-21 10:21:41 -0800609 List<StatsLogEventWrapper> ret = new ArrayList();
610 long token = Binder.clearCallingIdentity();
611 if (mTelephony == null) {
612 mTelephony = TelephonyManager.from(mContext);
613 }
614 if (mTelephony != null) {
615 SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
616 mTelephony.requestModemActivityInfo(modemReceiver);
617 final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
618 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
619 e.writeLong(modemInfo.getTimestamp());
620 e.writeLong(modemInfo.getSleepTimeMillis());
621 e.writeLong(modemInfo.getIdleTimeMillis());
622 e.writeLong(modemInfo.getTxTimeMillis()[0]);
623 e.writeLong(modemInfo.getTxTimeMillis()[1]);
624 e.writeLong(modemInfo.getTxTimeMillis()[2]);
625 e.writeLong(modemInfo.getTxTimeMillis()[3]);
626 e.writeLong(modemInfo.getTxTimeMillis()[4]);
627 e.writeLong(modemInfo.getRxTimeMillis());
628 e.writeLong(modemInfo.getEnergyUsed());
629 ret.add(e);
Chenjie Yu937d7422018-01-10 16:37:53 -0800630 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
Chenjie Yu05013b32017-11-21 10:21:41 -0800631 }
632 break;
633 }
Chenjie Yu9da105b2018-01-13 12:41:08 -0800634 case StatsLog.CPU_SUSPEND_TIME: {
635 List<StatsLogEventWrapper> ret = new ArrayList();
636 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
637 e.writeLong(SystemClock.elapsedRealtime());
638 ret.add(e);
Chenjie Yu937d7422018-01-10 16:37:53 -0800639 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
Chenjie Yu9da105b2018-01-13 12:41:08 -0800640 }
641 case StatsLog.CPU_IDLE_TIME: {
642 List<StatsLogEventWrapper> ret = new ArrayList();
643 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
644 e.writeLong(SystemClock.uptimeMillis());
645 ret.add(e);
Chenjie Yu937d7422018-01-10 16:37:53 -0800646 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
647 }
648 case StatsLog.DISK_SPACE: {
649 List<StatsLogEventWrapper> ret = new ArrayList();
650 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
651 e.writeLong(mStatFsData.getAvailableBytes());
652 e.writeLong(mStatFsSystem.getAvailableBytes());
653 e.writeLong(mStatFsTemp.getAvailableBytes());
654 ret.add(e);
655 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
656 }
657 case StatsLog.SYSTEM_UPTIME: {
658 List<StatsLogEventWrapper> ret = new ArrayList();
659 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
660 e.writeLong(SystemClock.uptimeMillis());
661 ret.add(e);
662 return ret.toArray(new StatsLogEventWrapper[ret.size()]);
Chenjie Yu9da105b2018-01-13 12:41:08 -0800663 }
Bookatzc68a9d22017-09-27 14:09:55 -0700664 default:
Chenjie Yu5305e1d2017-10-31 13:49:36 -0700665 Slog.w(TAG, "No such tagId data as " + tagId);
Bookatzc68a9d22017-09-27 14:09:55 -0700666 return null;
667 }
David Chenc8a43242017-10-17 16:23:28 -0700668 return null;
Bookatzc68a9d22017-09-27 14:09:55 -0700669 }
670
671 @Override // Binder call
Bookatzb487b552017-09-18 11:26:01 -0700672 public void statsdReady() {
673 enforceCallingPermission();
674 if (DEBUG) Slog.d(TAG, "learned that statsdReady");
675 sayHiToStatsd(); // tell statsd that we're ready too and link to it
676 }
677
David Chenc136f452017-11-27 11:52:26 -0800678 @Override
679 public void triggerUidSnapshot() {
680 enforceCallingPermission();
681 synchronized (sStatsdLock) {
682 try {
683 informAllUidsLocked(mContext);
684 } catch (RemoteException e) {
685 Slog.e(TAG, "Failed to trigger uid snapshot.", e);
686 }
687 }
688 }
689
Bookatz94726412017-08-31 09:26:15 -0700690 private void enforceCallingPermission() {
691 if (Binder.getCallingPid() == Process.myPid()) {
692 return;
693 }
694 mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
695 }
696
Bookatzb487b552017-09-18 11:26:01 -0700697 // Lifecycle and related code
698
David Chen1481fe12017-10-16 13:16:34 -0700699 /**
700 * Fetches the statsd IBinder service
701 */
Bookatzb487b552017-09-18 11:26:01 -0700702 private static IStatsManager fetchStatsdService() {
703 return IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
704 }
705
706 public static final class Lifecycle extends SystemService {
707 private StatsCompanionService mStatsCompanionService;
708
709 public Lifecycle(Context context) {
710 super(context);
711 }
712
713 @Override
714 public void onStart() {
715 mStatsCompanionService = new StatsCompanionService(getContext());
716 try {
717 publishBinderService(Context.STATS_COMPANION_SERVICE, mStatsCompanionService);
718 if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE);
719 } catch (Exception e) {
720 Slog.e(TAG, "Failed to publishBinderService", e);
721 }
722 }
723
724 @Override
725 public void onBootPhase(int phase) {
726 super.onBootPhase(phase);
727 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
728 mStatsCompanionService.systemReady();
729 }
730 }
731 }
732
David Chen1481fe12017-10-16 13:16:34 -0700733 /**
734 * Now that the android system is ready, StatsCompanion is ready too, so inform statsd.
735 */
Bookatzb487b552017-09-18 11:26:01 -0700736 private void systemReady() {
737 if (DEBUG) Slog.d(TAG, "Learned that systemReady");
738 sayHiToStatsd();
739 }
740
David Chen1481fe12017-10-16 13:16:34 -0700741 /**
742 * Tells statsd that statscompanion is ready. If the binder call returns, link to statsd.
743 */
Bookatzb487b552017-09-18 11:26:01 -0700744 private void sayHiToStatsd() {
745 synchronized (sStatsdLock) {
746 if (sStatsd != null) {
747 Slog.e(TAG, "Trying to fetch statsd, but it was already fetched",
748 new IllegalStateException("sStatsd is not null when being fetched"));
749 return;
750 }
751 sStatsd = fetchStatsdService();
752 if (sStatsd == null) {
753 Slog.w(TAG, "Could not access statsd");
754 return;
755 }
756 if (DEBUG) Slog.d(TAG, "Saying hi to statsd");
757 try {
758 sStatsd.statsCompanionReady();
759 // If the statsCompanionReady two-way binder call returns, link to statsd.
760 try {
761 sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
762 } catch (RemoteException e) {
763 Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
764 forgetEverything();
765 }
yro947fbce2017-11-15 22:50:23 -0800766 // Setup broadcast receiver for updates.
David Chende701692017-10-05 13:16:02 -0700767 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
768 filter.addAction(Intent.ACTION_PACKAGE_ADDED);
769 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
770 filter.addDataScheme("package");
771 mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null,
David Chen1481fe12017-10-16 13:16:34 -0700772 null);
David Chen47e8f4d2017-10-11 15:34:13 -0700773
774 // Setup receiver for user initialize (which happens once for a new user) and
775 // if a user is removed.
776 filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
777 filter.addAction(Intent.ACTION_USER_REMOVED);
778 mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL,
David Chen1481fe12017-10-16 13:16:34 -0700779 filter, null, null);
David Chen47e8f4d2017-10-11 15:34:13 -0700780
yro947fbce2017-11-15 22:50:23 -0800781 // Setup receiver for device reboots or shutdowns.
782 filter = new IntentFilter(Intent.ACTION_REBOOT);
783 filter.addAction(Intent.ACTION_SHUTDOWN);
784 mContext.registerReceiverAsUser(
785 mShutdownEventReceiver, UserHandle.ALL, filter, null, null);
Yao Chen0f217102018-01-09 10:33:15 -0800786 final long token = Binder.clearCallingIdentity();
787 try {
788 // Pull the latest state of UID->app name, version mapping when statsd starts.
789 informAllUidsLocked(mContext);
790 } finally {
791 restoreCallingIdentity(token);
792 }
Bookatzb487b552017-09-18 11:26:01 -0700793 } catch (RemoteException e) {
794 Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
795 forgetEverything();
796 }
797 }
798 }
799
800 private class StatsdDeathRecipient implements IBinder.DeathRecipient {
801 @Override
802 public void binderDied() {
803 Slog.i(TAG, "Statsd is dead - erase all my knowledge.");
804 forgetEverything();
805 }
806 }
807
808 private void forgetEverything() {
809 synchronized (sStatsdLock) {
810 sStatsd = null;
David Chende701692017-10-05 13:16:02 -0700811 mContext.unregisterReceiver(mAppUpdateReceiver);
David Chen47e8f4d2017-10-11 15:34:13 -0700812 mContext.unregisterReceiver(mUserUpdateReceiver);
yro947fbce2017-11-15 22:50:23 -0800813 mContext.unregisterReceiver(mShutdownEventReceiver);
Bookatzb487b552017-09-18 11:26:01 -0700814 cancelAnomalyAlarm();
Chenjie Yub3dda412017-10-24 13:41:59 -0700815 cancelPullingAlarms();
Bookatzb487b552017-09-18 11:26:01 -0700816 }
817 }
818
Bookatz94726412017-08-31 09:26:15 -0700819}