StatsCompanionService.java revision 369208256755a5ded185112dd2ceecadb5986fa5
1/* 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 18import android.annotation.Nullable; 19import android.app.AlarmManager; 20import android.app.PendingIntent; 21import android.app.StatsManager; 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.content.IntentSender; 27import android.content.pm.PackageInfo; 28import android.content.pm.PackageManager; 29import android.content.pm.UserInfo; 30import android.net.NetworkStats; 31import android.net.wifi.IWifiManager; 32import android.net.wifi.WifiActivityEnergyInfo; 33import android.os.StatsDimensionsValue; 34import android.os.BatteryStatsInternal; 35import android.os.Binder; 36import android.os.Bundle; 37import android.os.Environment; 38import android.os.IBinder; 39import android.os.IStatsCompanionService; 40import android.os.IStatsManager; 41import android.os.Parcelable; 42import android.os.Process; 43import android.os.RemoteException; 44import android.os.ServiceManager; 45import android.os.StatFs; 46import android.os.StatsLogEventWrapper; 47import android.os.SynchronousResultReceiver; 48import android.os.SystemClock; 49import android.os.UserHandle; 50import android.os.UserManager; 51import android.telephony.ModemActivityInfo; 52import android.telephony.TelephonyManager; 53import android.util.Slog; 54import android.util.StatsLog; 55 56import com.android.internal.annotations.GuardedBy; 57import com.android.internal.net.NetworkStatsFactory; 58import com.android.internal.os.KernelCpuSpeedReader; 59import com.android.internal.os.KernelWakelockReader; 60import com.android.internal.os.KernelWakelockStats; 61import com.android.internal.os.PowerProfile; 62import com.android.server.LocalServices; 63import com.android.server.SystemService; 64 65import java.util.ArrayList; 66import java.util.List; 67import java.util.Map; 68import java.util.concurrent.TimeoutException; 69 70/** 71 * Helper service for statsd (the native stats management service in cmds/statsd/). 72 * Used for registering and receiving alarms on behalf of statsd. 73 * 74 * @hide 75 */ 76public class StatsCompanionService extends IStatsCompanionService.Stub { 77 /** 78 * How long to wait on an individual subsystem to return its stats. 79 */ 80 private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000; 81 82 public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity"; 83 84 static final String TAG = "StatsCompanionService"; 85 static final boolean DEBUG = true; 86 87 public static final String ACTION_TRIGGER_COLLECTION = 88 "com.android.server.stats.action.TRIGGER_COLLECTION"; 89 90 public static final int CODE_SUBSCRIBER_BROADCAST = 1; 91 92 private final Context mContext; 93 private final AlarmManager mAlarmManager; 94 @GuardedBy("sStatsdLock") 95 private static IStatsManager sStatsd; 96 private static final Object sStatsdLock = new Object(); 97 98 private final PendingIntent mAnomalyAlarmIntent; 99 private final PendingIntent mPullingAlarmIntent; 100 private final BroadcastReceiver mAppUpdateReceiver; 101 private final BroadcastReceiver mUserUpdateReceiver; 102 private final ShutdownEventReceiver mShutdownEventReceiver; 103 private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader(); 104 private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); 105 private final KernelCpuSpeedReader[] mKernelCpuSpeedReaders; 106 private IWifiManager mWifiManager = null; 107 private TelephonyManager mTelephony = null; 108 private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath()); 109 private final StatFs mStatFsSystem = 110 new StatFs(Environment.getRootDirectory().getAbsolutePath()); 111 private final StatFs mStatFsTemp = 112 new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath()); 113 114 public StatsCompanionService(Context context) { 115 super(); 116 mContext = context; 117 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 118 119 mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0, 120 new Intent(mContext, AnomalyAlarmReceiver.class), 0); 121 mPullingAlarmIntent = PendingIntent.getBroadcast( 122 mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0); 123 mAppUpdateReceiver = new AppUpdateReceiver(); 124 mUserUpdateReceiver = new BroadcastReceiver() { 125 @Override 126 public void onReceive(Context context, Intent intent) { 127 synchronized (sStatsdLock) { 128 sStatsd = fetchStatsdService(); 129 if (sStatsd == null) { 130 Slog.w(TAG, "Could not access statsd"); 131 return; 132 } 133 try { 134 // Pull the latest state of UID->app name, version mapping. 135 // Needed since the new user basically has a version of every app. 136 informAllUidsLocked(context); 137 } catch (RemoteException e) { 138 Slog.e(TAG, "Failed to inform statsd latest update of all apps", e); 139 forgetEverything(); 140 } 141 } 142 } 143 }; 144 mShutdownEventReceiver = new ShutdownEventReceiver(); 145 Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED."); 146 PowerProfile powerProfile = new PowerProfile(context); 147 final int numClusters = powerProfile.getNumCpuClusters(); 148 mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters]; 149 int firstCpuOfCluster = 0; 150 for (int i = 0; i < numClusters; i++) { 151 final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i); 152 mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster, 153 numSpeedSteps); 154 firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i); 155 } 156 } 157 158 @Override 159 public void sendBroadcast(String pkg, String cls) { 160 // TODO: Use a pending intent. 161 enforceCallingPermission(); 162 mContext.sendBroadcastAsUser(new Intent(ACTION_TRIGGER_COLLECTION).setClassName(pkg, cls), 163 UserHandle.SYSTEM); 164 } 165 166 @Override 167 public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey, 168 long subscriptionId, long subscriptionRuleId, 169 StatsDimensionsValue dimensionsValue) { 170 if (DEBUG) Slog.d(TAG, "Statsd requested to sendSubscriberBroadcast."); 171 enforceCallingPermission(); 172 IntentSender intentSender = new IntentSender(intentSenderBinder); 173 Intent intent = new Intent() 174 .putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid) 175 .putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configKey) 176 .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId) 177 .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId) 178 .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue); 179 try { 180 intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null); 181 } catch (IntentSender.SendIntentException e) { 182 Slog.w(TAG, "Unable to send using IntentSender from uid " + configUid 183 + "; presumably it had been cancelled."); 184 if (DEBUG) { 185 Slog.d(TAG, String.format("SubscriberBroadcast params {%d %d %d %d %s}", 186 configUid, configKey, subscriptionId, 187 subscriptionRuleId, dimensionsValue)); 188 } 189 } 190 } 191 192 private final static int[] toIntArray(List<Integer> list) { 193 int[] ret = new int[list.size()]; 194 for (int i = 0; i < ret.length; i++) { 195 ret[i] = list.get(i); 196 } 197 return ret; 198 } 199 200 private final static long[] toLongArray(List<Long> list) { 201 long[] ret = new long[list.size()]; 202 for (int i = 0; i < ret.length; i++) { 203 ret[i] = list.get(i); 204 } 205 return ret; 206 } 207 208 // Assumes that sStatsdLock is held. 209 private final void informAllUidsLocked(Context context) throws RemoteException { 210 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 211 PackageManager pm = context.getPackageManager(); 212 final List<UserInfo> users = um.getUsers(true); 213 if (DEBUG) { 214 Slog.w(TAG, "Iterating over " + users.size() + " profiles."); 215 } 216 217 List<Integer> uids = new ArrayList(); 218 List<Long> versions = new ArrayList(); 219 List<String> apps = new ArrayList(); 220 221 // Add in all the apps for every user/profile. 222 for (UserInfo profile : users) { 223 List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id); 224 for (int j = 0; j < pi.size(); j++) { 225 if (pi.get(j).applicationInfo != null) { 226 uids.add(pi.get(j).applicationInfo.uid); 227 versions.add(pi.get(j).getLongVersionCode()); 228 apps.add(pi.get(j).packageName); 229 } 230 } 231 } 232 sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new 233 String[apps.size()])); 234 if (DEBUG) { 235 Slog.w(TAG, "Sent data for " + uids.size() + " apps"); 236 } 237 } 238 239 private final static class AppUpdateReceiver extends BroadcastReceiver { 240 @Override 241 public void onReceive(Context context, Intent intent) { 242 /** 243 * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid 244 * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag. 245 * If we can't find the value for EXTRA_REPLACING, we default to false. 246 */ 247 if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) 248 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 249 return; // Keep only replacing or normal add and remove. 250 } 251 Slog.i(TAG, "StatsCompanionService noticed an app was updated."); 252 synchronized (sStatsdLock) { 253 if (sStatsd == null) { 254 Slog.w(TAG, "Could not access statsd to inform it of an app update"); 255 return; 256 } 257 try { 258 if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { 259 Bundle b = intent.getExtras(); 260 int uid = b.getInt(Intent.EXTRA_UID); 261 boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 262 if (!replacing) { 263 // Don't bother sending an update if we're right about to get another 264 // intent for the new version that's added. 265 PackageManager pm = context.getPackageManager(); 266 String app = intent.getData().getSchemeSpecificPart(); 267 sStatsd.informOnePackageRemoved(app, uid); 268 } 269 } else { 270 PackageManager pm = context.getPackageManager(); 271 Bundle b = intent.getExtras(); 272 int uid = b.getInt(Intent.EXTRA_UID); 273 String app = intent.getData().getSchemeSpecificPart(); 274 PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER); 275 sStatsd.informOnePackage(app, uid, pi.getLongVersionCode()); 276 } 277 } catch (Exception e) { 278 Slog.w(TAG, "Failed to inform statsd of an app update", e); 279 } 280 } 281 } 282 } 283 284 private final static class AnomalyAlarmReceiver extends BroadcastReceiver { 285 @Override 286 public void onReceive(Context context, Intent intent) { 287 Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred."); 288 synchronized (sStatsdLock) { 289 if (sStatsd == null) { 290 Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); 291 return; 292 } 293 try { 294 // Two-way call to statsd to retain AlarmManager wakelock 295 sStatsd.informAnomalyAlarmFired(); 296 } catch (RemoteException e) { 297 Slog.w(TAG, "Failed to inform statsd of anomaly alarm firing", e); 298 } 299 } 300 // AlarmManager releases its own wakelock here. 301 } 302 } 303 304 private final static class PullingAlarmReceiver extends BroadcastReceiver { 305 @Override 306 public void onReceive(Context context, Intent intent) { 307 if (DEBUG) 308 Slog.d(TAG, "Time to poll something."); 309 synchronized (sStatsdLock) { 310 if (sStatsd == null) { 311 Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing."); 312 return; 313 } 314 try { 315 // Two-way call to statsd to retain AlarmManager wakelock 316 sStatsd.informPollAlarmFired(); 317 } catch (RemoteException e) { 318 Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e); 319 } 320 } 321 // AlarmManager releases its own wakelock here. 322 } 323 } 324 325 private final static class ShutdownEventReceiver extends BroadcastReceiver { 326 @Override 327 public void onReceive(Context context, Intent intent) { 328 /** 329 * Skip immediately if intent is not relevant to device shutdown. 330 */ 331 if (!intent.getAction().equals(Intent.ACTION_REBOOT) 332 && !intent.getAction().equals(Intent.ACTION_SHUTDOWN)) { 333 return; 334 } 335 Slog.i(TAG, "StatsCompanionService noticed a shutdown."); 336 synchronized (sStatsdLock) { 337 if (sStatsd == null) { 338 Slog.w(TAG, "Could not access statsd to inform it of a shutdown event."); 339 return; 340 } 341 try { 342 sStatsd.writeDataToDisk(); 343 } catch (Exception e) { 344 Slog.w(TAG, "Failed to inform statsd of a shutdown event.", e); 345 } 346 } 347 } 348 } 349 350 @Override // Binder call 351 public void setAnomalyAlarm(long timestampMs) { 352 enforceCallingPermission(); 353 if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs); 354 final long callingToken = Binder.clearCallingIdentity(); 355 try { 356 // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens. 357 // This alarm is inexact, leaving its exactness completely up to the OS optimizations. 358 // AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm. 359 mAlarmManager.set(AlarmManager.RTC, timestampMs, mAnomalyAlarmIntent); 360 } finally { 361 Binder.restoreCallingIdentity(callingToken); 362 } 363 } 364 365 @Override // Binder call 366 public void cancelAnomalyAlarm() { 367 enforceCallingPermission(); 368 if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm"); 369 final long callingToken = Binder.clearCallingIdentity(); 370 try { 371 mAlarmManager.cancel(mAnomalyAlarmIntent); 372 } finally { 373 Binder.restoreCallingIdentity(callingToken); 374 } 375 } 376 377 @Override // Binder call 378 public void setPullingAlarms(long timestampMs, long intervalMs) { 379 enforceCallingPermission(); 380 if (DEBUG) 381 Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms"); 382 final long callingToken = Binder.clearCallingIdentity(); 383 try { 384 // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens. 385 // This alarm is inexact, leaving its exactness completely up to the OS optimizations. 386 // TODO: totally inexact means that stats per bucket could be quite off. Is this okay? 387 mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent); 388 } finally { 389 Binder.restoreCallingIdentity(callingToken); 390 } 391 } 392 393 @Override // Binder call 394 public void cancelPullingAlarms() { 395 enforceCallingPermission(); 396 if (DEBUG) 397 Slog.d(TAG, "Cancelling pulling alarm"); 398 final long callingToken = Binder.clearCallingIdentity(); 399 try { 400 mAlarmManager.cancel(mPullingAlarmIntent); 401 } finally { 402 Binder.restoreCallingIdentity(callingToken); 403 } 404 } 405 406 private StatsLogEventWrapper[] addNetworkStats(int tag, NetworkStats stats, boolean withFGBG) { 407 List<StatsLogEventWrapper> ret = new ArrayList<>(); 408 int size = stats.size(); 409 NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling 410 for (int j = 0; j < size; j++) { 411 stats.getValues(j, entry); 412 StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5); 413 e.writeInt(entry.uid); 414 if (withFGBG) { 415 e.writeInt(entry.set); 416 } 417 e.writeLong(entry.rxBytes); 418 e.writeLong(entry.rxPackets); 419 e.writeLong(entry.txBytes); 420 e.writeLong(entry.txPackets); 421 ret.add(e); 422 } 423 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 424 } 425 426 /** 427 * Allows rollups per UID but keeping the set (foreground/background) slicing. 428 * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java 429 */ 430 private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) { 431 final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); 432 433 final NetworkStats.Entry entry = new NetworkStats.Entry(); 434 entry.iface = NetworkStats.IFACE_ALL; 435 entry.tag = NetworkStats.TAG_NONE; 436 entry.metered = NetworkStats.METERED_ALL; 437 entry.roaming = NetworkStats.ROAMING_ALL; 438 439 int size = stats.size(); 440 NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values 441 for (int i = 0; i < size; i++) { 442 stats.getValues(i, recycle); 443 444 // Skip specific tags, since already counted in TAG_NONE 445 if (recycle.tag != NetworkStats.TAG_NONE) continue; 446 447 entry.set = recycle.set; // Allows slicing by background/foreground 448 entry.uid = recycle.uid; 449 entry.rxBytes = recycle.rxBytes; 450 entry.rxPackets = recycle.rxPackets; 451 entry.txBytes = recycle.txBytes; 452 entry.txPackets = recycle.txPackets; 453 // Operations purposefully omitted since we don't use them for statsd. 454 ret.combineValues(entry); 455 } 456 return ret; 457 } 458 459 /** 460 * Helper method to extract the Parcelable controller info from a 461 * SynchronousResultReceiver. 462 */ 463 private static <T extends Parcelable> T awaitControllerInfo( 464 @Nullable SynchronousResultReceiver receiver) { 465 if (receiver == null) { 466 return null; 467 } 468 469 try { 470 final SynchronousResultReceiver.Result result = 471 receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS); 472 if (result.bundle != null) { 473 // This is the final destination for the Bundle. 474 result.bundle.setDefusable(true); 475 476 final T data = result.bundle.getParcelable( 477 RESULT_RECEIVER_CONTROLLER_KEY); 478 if (data != null) { 479 return data; 480 } 481 } 482 Slog.e(TAG, "no controller energy info supplied for " + receiver.getName()); 483 } catch (TimeoutException e) { 484 Slog.w(TAG, "timeout reading " + receiver.getName() + " stats"); 485 } 486 return null; 487 } 488 489 /** 490 * 491 * Pulls wifi controller activity energy info from WiFiManager 492 */ 493 @Override // Binder call 494 public StatsLogEventWrapper[] pullData(int tagId) { 495 enforceCallingPermission(); 496 if (DEBUG) 497 Slog.d(TAG, "Pulling " + tagId); 498 499 switch (tagId) { 500 case StatsLog.WIFI_BYTES_TRANSFER: { 501 long token = Binder.clearCallingIdentity(); 502 try { 503 // TODO: Consider caching the following call to get BatteryStatsInternal. 504 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); 505 String[] ifaces = bs.getWifiIfaces(); 506 if (ifaces.length == 0) { 507 return null; 508 } 509 NetworkStatsFactory nsf = new NetworkStatsFactory(); 510 // Combine all the metrics per Uid into one record. 511 NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, 512 NetworkStats.TAG_NONE, null).groupedByUid(); 513 return addNetworkStats(tagId, stats, false); 514 } catch (java.io.IOException e) { 515 Slog.e(TAG, "Pulling netstats for wifi bytes has error", e); 516 } finally { 517 Binder.restoreCallingIdentity(token); 518 } 519 break; 520 } 521 case StatsLog.MOBILE_BYTES_TRANSFER: { 522 long token = Binder.clearCallingIdentity(); 523 try { 524 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); 525 String[] ifaces = bs.getMobileIfaces(); 526 if (ifaces.length == 0) { 527 return null; 528 } 529 NetworkStatsFactory nsf = new NetworkStatsFactory(); 530 // Combine all the metrics per Uid into one record. 531 NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, 532 NetworkStats.TAG_NONE, null).groupedByUid(); 533 return addNetworkStats(tagId, stats, false); 534 } catch (java.io.IOException e) { 535 Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); 536 } finally { 537 Binder.restoreCallingIdentity(token); 538 } 539 break; 540 } 541 case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: { 542 long token = Binder.clearCallingIdentity(); 543 try { 544 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); 545 String[] ifaces = bs.getWifiIfaces(); 546 if (ifaces.length == 0) { 547 return null; 548 } 549 NetworkStatsFactory nsf = new NetworkStatsFactory(); 550 NetworkStats stats = rollupNetworkStatsByFGBG( 551 nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, 552 NetworkStats.TAG_NONE, null)); 553 return addNetworkStats(tagId, stats, true); 554 } catch (java.io.IOException e) { 555 Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); 556 } finally { 557 Binder.restoreCallingIdentity(token); 558 } 559 break; 560 } 561 case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: { 562 long token = Binder.clearCallingIdentity(); 563 try { 564 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); 565 String[] ifaces = bs.getMobileIfaces(); 566 if (ifaces.length == 0) { 567 return null; 568 } 569 NetworkStatsFactory nsf = new NetworkStatsFactory(); 570 NetworkStats stats = rollupNetworkStatsByFGBG( 571 nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, 572 NetworkStats.TAG_NONE, null)); 573 return addNetworkStats(tagId, stats, true); 574 } catch (java.io.IOException e) { 575 Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); 576 } finally { 577 Binder.restoreCallingIdentity(token); 578 } 579 break; 580 } 581 case StatsLog.KERNEL_WAKELOCK: { 582 final KernelWakelockStats wakelockStats = 583 mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats); 584 List<StatsLogEventWrapper> ret = new ArrayList(); 585 for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) { 586 String name = ent.getKey(); 587 KernelWakelockStats.Entry kws = ent.getValue(); 588 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4); 589 e.writeString(name); 590 e.writeInt(kws.mCount); 591 e.writeInt(kws.mVersion); 592 e.writeLong(kws.mTotalTime); 593 ret.add(e); 594 } 595 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 596 } 597 case StatsLog.CPU_TIME_PER_FREQ: { 598 List<StatsLogEventWrapper> ret = new ArrayList(); 599 for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) { 600 long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute(); 601 if (clusterTimeMs != null) { 602 for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) { 603 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3); 604 e.writeInt(cluster); 605 e.writeInt(speed); 606 e.writeLong(clusterTimeMs[speed]); 607 ret.add(e); 608 } 609 } 610 } 611 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 612 } 613 case StatsLog.WIFI_ACTIVITY_ENERGY_INFO: { 614 List<StatsLogEventWrapper> ret = new ArrayList(); 615 long token = Binder.clearCallingIdentity(); 616 if (mWifiManager == null) { 617 mWifiManager = IWifiManager.Stub.asInterface(ServiceManager.getService( 618 Context.WIFI_SERVICE)); 619 } 620 if (mWifiManager != null) { 621 try { 622 SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi"); 623 mWifiManager.requestActivityInfo(wifiReceiver); 624 final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver); 625 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6); 626 e.writeLong(wifiInfo.getTimeStamp()); 627 e.writeInt(wifiInfo.getStackState()); 628 e.writeLong(wifiInfo.getControllerTxTimeMillis()); 629 e.writeLong(wifiInfo.getControllerRxTimeMillis()); 630 e.writeLong(wifiInfo.getControllerIdleTimeMillis()); 631 e.writeLong(wifiInfo.getControllerEnergyUsed()); 632 ret.add(e); 633 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 634 } catch (RemoteException e) { 635 Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e); 636 } finally { 637 Binder.restoreCallingIdentity(token); 638 } 639 } 640 break; 641 } 642 case StatsLog.MODEM_ACTIVITY_INFO: { 643 List<StatsLogEventWrapper> ret = new ArrayList(); 644 long token = Binder.clearCallingIdentity(); 645 if (mTelephony == null) { 646 mTelephony = TelephonyManager.from(mContext); 647 } 648 if (mTelephony != null) { 649 SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony"); 650 mTelephony.requestModemActivityInfo(modemReceiver); 651 final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver); 652 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6); 653 e.writeLong(modemInfo.getTimestamp()); 654 e.writeLong(modemInfo.getSleepTimeMillis()); 655 e.writeLong(modemInfo.getIdleTimeMillis()); 656 e.writeLong(modemInfo.getTxTimeMillis()[0]); 657 e.writeLong(modemInfo.getTxTimeMillis()[1]); 658 e.writeLong(modemInfo.getTxTimeMillis()[2]); 659 e.writeLong(modemInfo.getTxTimeMillis()[3]); 660 e.writeLong(modemInfo.getTxTimeMillis()[4]); 661 e.writeLong(modemInfo.getRxTimeMillis()); 662 e.writeLong(modemInfo.getEnergyUsed()); 663 ret.add(e); 664 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 665 } 666 break; 667 } 668 case StatsLog.CPU_SUSPEND_TIME: { 669 List<StatsLogEventWrapper> ret = new ArrayList(); 670 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1); 671 e.writeLong(SystemClock.elapsedRealtime()); 672 ret.add(e); 673 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 674 } 675 case StatsLog.CPU_IDLE_TIME: { 676 List<StatsLogEventWrapper> ret = new ArrayList(); 677 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1); 678 e.writeLong(SystemClock.uptimeMillis()); 679 ret.add(e); 680 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 681 } 682 case StatsLog.DISK_SPACE: { 683 List<StatsLogEventWrapper> ret = new ArrayList(); 684 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3); 685 e.writeLong(mStatFsData.getAvailableBytes()); 686 e.writeLong(mStatFsSystem.getAvailableBytes()); 687 e.writeLong(mStatFsTemp.getAvailableBytes()); 688 ret.add(e); 689 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 690 } 691 case StatsLog.SYSTEM_UPTIME: { 692 List<StatsLogEventWrapper> ret = new ArrayList(); 693 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1); 694 e.writeLong(SystemClock.uptimeMillis()); 695 ret.add(e); 696 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 697 } 698 default: 699 Slog.w(TAG, "No such tagId data as " + tagId); 700 return null; 701 } 702 return null; 703 } 704 705 @Override // Binder call 706 public void statsdReady() { 707 enforceCallingPermission(); 708 if (DEBUG) Slog.d(TAG, "learned that statsdReady"); 709 sayHiToStatsd(); // tell statsd that we're ready too and link to it 710 mContext.sendBroadcast(new Intent(StatsManager.ACTION_STATSD_STARTED), 711 android.Manifest.permission.DUMP); 712 } 713 714 @Override 715 public void triggerUidSnapshot() { 716 enforceCallingPermission(); 717 synchronized (sStatsdLock) { 718 try { 719 informAllUidsLocked(mContext); 720 } catch (RemoteException e) { 721 Slog.e(TAG, "Failed to trigger uid snapshot.", e); 722 } 723 } 724 } 725 726 private void enforceCallingPermission() { 727 if (Binder.getCallingPid() == Process.myPid()) { 728 return; 729 } 730 mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null); 731 } 732 733 // Lifecycle and related code 734 735 /** 736 * Fetches the statsd IBinder service 737 */ 738 private static IStatsManager fetchStatsdService() { 739 return IStatsManager.Stub.asInterface(ServiceManager.getService("stats")); 740 } 741 742 public static final class Lifecycle extends SystemService { 743 private StatsCompanionService mStatsCompanionService; 744 745 public Lifecycle(Context context) { 746 super(context); 747 } 748 749 @Override 750 public void onStart() { 751 mStatsCompanionService = new StatsCompanionService(getContext()); 752 try { 753 publishBinderService(Context.STATS_COMPANION_SERVICE, mStatsCompanionService); 754 if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE); 755 } catch (Exception e) { 756 Slog.e(TAG, "Failed to publishBinderService", e); 757 } 758 } 759 760 @Override 761 public void onBootPhase(int phase) { 762 super.onBootPhase(phase); 763 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 764 mStatsCompanionService.systemReady(); 765 } 766 } 767 } 768 769 /** 770 * Now that the android system is ready, StatsCompanion is ready too, so inform statsd. 771 */ 772 private void systemReady() { 773 if (DEBUG) Slog.d(TAG, "Learned that systemReady"); 774 sayHiToStatsd(); 775 } 776 777 /** 778 * Tells statsd that statscompanion is ready. If the binder call returns, link to statsd. 779 */ 780 private void sayHiToStatsd() { 781 synchronized (sStatsdLock) { 782 if (sStatsd != null) { 783 Slog.e(TAG, "Trying to fetch statsd, but it was already fetched", 784 new IllegalStateException("sStatsd is not null when being fetched")); 785 return; 786 } 787 sStatsd = fetchStatsdService(); 788 if (sStatsd == null) { 789 Slog.w(TAG, "Could not access statsd"); 790 return; 791 } 792 if (DEBUG) Slog.d(TAG, "Saying hi to statsd"); 793 try { 794 sStatsd.statsCompanionReady(); 795 // If the statsCompanionReady two-way binder call returns, link to statsd. 796 try { 797 sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0); 798 } catch (RemoteException e) { 799 Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e); 800 forgetEverything(); 801 } 802 // Setup broadcast receiver for updates. 803 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED); 804 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 805 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 806 filter.addDataScheme("package"); 807 mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null, 808 null); 809 810 // Setup receiver for user initialize (which happens once for a new user) and 811 // if a user is removed. 812 filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE); 813 filter.addAction(Intent.ACTION_USER_REMOVED); 814 mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL, 815 filter, null, null); 816 817 // Setup receiver for device reboots or shutdowns. 818 filter = new IntentFilter(Intent.ACTION_REBOOT); 819 filter.addAction(Intent.ACTION_SHUTDOWN); 820 mContext.registerReceiverAsUser( 821 mShutdownEventReceiver, UserHandle.ALL, filter, null, null); 822 final long token = Binder.clearCallingIdentity(); 823 try { 824 // Pull the latest state of UID->app name, version mapping when statsd starts. 825 informAllUidsLocked(mContext); 826 } finally { 827 restoreCallingIdentity(token); 828 } 829 } catch (RemoteException e) { 830 Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e); 831 forgetEverything(); 832 } 833 } 834 } 835 836 private class StatsdDeathRecipient implements IBinder.DeathRecipient { 837 @Override 838 public void binderDied() { 839 Slog.i(TAG, "Statsd is dead - erase all my knowledge."); 840 forgetEverything(); 841 } 842 } 843 844 private void forgetEverything() { 845 synchronized (sStatsdLock) { 846 sStatsd = null; 847 mContext.unregisterReceiver(mAppUpdateReceiver); 848 mContext.unregisterReceiver(mUserUpdateReceiver); 849 mContext.unregisterReceiver(mShutdownEventReceiver); 850 cancelAnomalyAlarm(); 851 cancelPullingAlarms(); 852 } 853 } 854 855} 856