StatsCompanionService.java revision 0eb58ae39d88a2fbfecabae8b10a4be5e4ebcc8c
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, and enfoceCallingPermission. 161 mContext.sendBroadcastAsUser(new Intent(ACTION_TRIGGER_COLLECTION).setClassName(pkg, cls), 162 UserHandle.SYSTEM); 163 } 164 165 @Override 166 public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey, 167 long subscriptionId, long subscriptionRuleId, 168 StatsDimensionsValue dimensionsValue) { 169 if (DEBUG) Slog.d(TAG, "Statsd requested to sendSubscriberBroadcast."); 170 enforceCallingPermission(); 171 IntentSender intentSender = new IntentSender(intentSenderBinder); 172 Intent intent = new Intent() 173 .putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid) 174 .putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configKey) 175 .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId) 176 .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId) 177 .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue); 178 try { 179 intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null); 180 } catch (IntentSender.SendIntentException e) { 181 Slog.w(TAG, "Unable to send using IntentSender from uid " + configUid 182 + "; presumably it had been cancelled."); 183 if (DEBUG) { 184 Slog.d(TAG, String.format("SubscriberBroadcast params {%d %d %d %d %s}", 185 configUid, configKey, subscriptionId, 186 subscriptionRuleId, dimensionsValue)); 187 } 188 } 189 } 190 191 private final static int[] toIntArray(List<Integer> list) { 192 int[] ret = new int[list.size()]; 193 for (int i = 0; i < ret.length; i++) { 194 ret[i] = list.get(i); 195 } 196 return ret; 197 } 198 199 private final static long[] toLongArray(List<Long> list) { 200 long[] ret = new long[list.size()]; 201 for (int i = 0; i < ret.length; i++) { 202 ret[i] = list.get(i); 203 } 204 return ret; 205 } 206 207 // Assumes that sStatsdLock is held. 208 private final void informAllUidsLocked(Context context) throws RemoteException { 209 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 210 PackageManager pm = context.getPackageManager(); 211 final List<UserInfo> users = um.getUsers(true); 212 if (DEBUG) { 213 Slog.w(TAG, "Iterating over " + users.size() + " profiles."); 214 } 215 216 List<Integer> uids = new ArrayList(); 217 List<Long> versions = new ArrayList(); 218 List<String> apps = new ArrayList(); 219 220 // Add in all the apps for every user/profile. 221 for (UserInfo profile : users) { 222 List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id); 223 for (int j = 0; j < pi.size(); j++) { 224 if (pi.get(j).applicationInfo != null) { 225 uids.add(pi.get(j).applicationInfo.uid); 226 versions.add(pi.get(j).getLongVersionCode()); 227 apps.add(pi.get(j).packageName); 228 } 229 } 230 } 231 sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new 232 String[apps.size()])); 233 if (DEBUG) { 234 Slog.w(TAG, "Sent data for " + uids.size() + " apps"); 235 } 236 } 237 238 public final static class AppUpdateReceiver extends BroadcastReceiver { 239 @Override 240 public void onReceive(Context context, Intent intent) { 241 /** 242 * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid 243 * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag. 244 * If we can't find the value for EXTRA_REPLACING, we default to false. 245 */ 246 if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) 247 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 248 return; // Keep only replacing or normal add and remove. 249 } 250 Slog.i(TAG, "StatsCompanionService noticed an app was updated."); 251 synchronized (sStatsdLock) { 252 if (sStatsd == null) { 253 Slog.w(TAG, "Could not access statsd to inform it of an app update"); 254 return; 255 } 256 try { 257 if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { 258 Bundle b = intent.getExtras(); 259 int uid = b.getInt(Intent.EXTRA_UID); 260 boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 261 if (!replacing) { 262 // Don't bother sending an update if we're right about to get another 263 // intent for the new version that's added. 264 PackageManager pm = context.getPackageManager(); 265 String app = intent.getData().getSchemeSpecificPart(); 266 sStatsd.informOnePackageRemoved(app, uid); 267 } 268 } else { 269 PackageManager pm = context.getPackageManager(); 270 Bundle b = intent.getExtras(); 271 int uid = b.getInt(Intent.EXTRA_UID); 272 String app = intent.getData().getSchemeSpecificPart(); 273 PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER); 274 sStatsd.informOnePackage(app, uid, pi.getLongVersionCode()); 275 } 276 } catch (Exception e) { 277 Slog.w(TAG, "Failed to inform statsd of an app update", e); 278 } 279 } 280 } 281 } 282 283 public final static class AnomalyAlarmReceiver extends BroadcastReceiver { 284 @Override 285 public void onReceive(Context context, Intent intent) { 286 Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred."); 287 synchronized (sStatsdLock) { 288 if (sStatsd == null) { 289 Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); 290 return; 291 } 292 try { 293 // Two-way call to statsd to retain AlarmManager wakelock 294 sStatsd.informAnomalyAlarmFired(); 295 } catch (RemoteException e) { 296 Slog.w(TAG, "Failed to inform statsd of anomaly alarm firing", e); 297 } 298 } 299 // AlarmManager releases its own wakelock here. 300 } 301 } 302 303 public final static class PullingAlarmReceiver extends BroadcastReceiver { 304 @Override 305 public void onReceive(Context context, Intent intent) { 306 if (DEBUG) 307 Slog.d(TAG, "Time to poll something."); 308 synchronized (sStatsdLock) { 309 if (sStatsd == null) { 310 Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing."); 311 return; 312 } 313 try { 314 // Two-way call to statsd to retain AlarmManager wakelock 315 sStatsd.informPollAlarmFired(); 316 } catch (RemoteException e) { 317 Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e); 318 } 319 } 320 // AlarmManager releases its own wakelock here. 321 } 322 } 323 324 public final static class ShutdownEventReceiver extends BroadcastReceiver { 325 @Override 326 public void onReceive(Context context, Intent intent) { 327 /** 328 * Skip immediately if intent is not relevant to device shutdown. 329 */ 330 if (!intent.getAction().equals(Intent.ACTION_REBOOT) 331 && !intent.getAction().equals(Intent.ACTION_SHUTDOWN)) { 332 return; 333 } 334 Slog.i(TAG, "StatsCompanionService noticed a shutdown."); 335 synchronized (sStatsdLock) { 336 if (sStatsd == null) { 337 Slog.w(TAG, "Could not access statsd to inform it of a shutdown event."); 338 return; 339 } 340 try { 341 sStatsd.writeDataToDisk(); 342 } catch (Exception e) { 343 Slog.w(TAG, "Failed to inform statsd of a shutdown event.", e); 344 } 345 } 346 } 347 } 348 349 @Override // Binder call 350 public void setAnomalyAlarm(long timestampMs) { 351 enforceCallingPermission(); 352 if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs); 353 final long callingToken = Binder.clearCallingIdentity(); 354 try { 355 // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens. 356 // This alarm is inexact, leaving its exactness completely up to the OS optimizations. 357 // AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm. 358 mAlarmManager.set(AlarmManager.RTC, timestampMs, mAnomalyAlarmIntent); 359 } finally { 360 Binder.restoreCallingIdentity(callingToken); 361 } 362 } 363 364 @Override // Binder call 365 public void cancelAnomalyAlarm() { 366 enforceCallingPermission(); 367 if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm"); 368 final long callingToken = Binder.clearCallingIdentity(); 369 try { 370 mAlarmManager.cancel(mAnomalyAlarmIntent); 371 } finally { 372 Binder.restoreCallingIdentity(callingToken); 373 } 374 } 375 376 @Override // Binder call 377 public void setPullingAlarms(long timestampMs, long intervalMs) { 378 enforceCallingPermission(); 379 if (DEBUG) 380 Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms"); 381 final long callingToken = Binder.clearCallingIdentity(); 382 try { 383 // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens. 384 // This alarm is inexact, leaving its exactness completely up to the OS optimizations. 385 // TODO: totally inexact means that stats per bucket could be quite off. Is this okay? 386 mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent); 387 } finally { 388 Binder.restoreCallingIdentity(callingToken); 389 } 390 } 391 392 @Override // Binder call 393 public void cancelPullingAlarms() { 394 enforceCallingPermission(); 395 if (DEBUG) 396 Slog.d(TAG, "Cancelling pulling alarm"); 397 final long callingToken = Binder.clearCallingIdentity(); 398 try { 399 mAlarmManager.cancel(mPullingAlarmIntent); 400 } finally { 401 Binder.restoreCallingIdentity(callingToken); 402 } 403 } 404 405 private StatsLogEventWrapper[] addNetworkStats(int tag, NetworkStats stats, boolean withFGBG) { 406 List<StatsLogEventWrapper> ret = new ArrayList<>(); 407 int size = stats.size(); 408 NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling 409 for (int j = 0; j < size; j++) { 410 stats.getValues(j, entry); 411 StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5); 412 e.writeInt(entry.uid); 413 if (withFGBG) { 414 e.writeInt(entry.set); 415 } 416 e.writeLong(entry.rxBytes); 417 e.writeLong(entry.rxPackets); 418 e.writeLong(entry.txBytes); 419 e.writeLong(entry.txPackets); 420 ret.add(e); 421 } 422 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 423 } 424 425 /** 426 * Allows rollups per UID but keeping the set (foreground/background) slicing. 427 * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java 428 */ 429 private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) { 430 final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); 431 432 final NetworkStats.Entry entry = new NetworkStats.Entry(); 433 entry.iface = NetworkStats.IFACE_ALL; 434 entry.tag = NetworkStats.TAG_NONE; 435 entry.metered = NetworkStats.METERED_ALL; 436 entry.roaming = NetworkStats.ROAMING_ALL; 437 438 int size = stats.size(); 439 NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values 440 for (int i = 0; i < size; i++) { 441 stats.getValues(i, recycle); 442 443 // Skip specific tags, since already counted in TAG_NONE 444 if (recycle.tag != NetworkStats.TAG_NONE) continue; 445 446 entry.set = recycle.set; // Allows slicing by background/foreground 447 entry.uid = recycle.uid; 448 entry.rxBytes = recycle.rxBytes; 449 entry.rxPackets = recycle.rxPackets; 450 entry.txBytes = recycle.txBytes; 451 entry.txPackets = recycle.txPackets; 452 // Operations purposefully omitted since we don't use them for statsd. 453 ret.combineValues(entry); 454 } 455 return ret; 456 } 457 458 /** 459 * Helper method to extract the Parcelable controller info from a 460 * SynchronousResultReceiver. 461 */ 462 private static <T extends Parcelable> T awaitControllerInfo( 463 @Nullable SynchronousResultReceiver receiver) { 464 if (receiver == null) { 465 return null; 466 } 467 468 try { 469 final SynchronousResultReceiver.Result result = 470 receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS); 471 if (result.bundle != null) { 472 // This is the final destination for the Bundle. 473 result.bundle.setDefusable(true); 474 475 final T data = result.bundle.getParcelable( 476 RESULT_RECEIVER_CONTROLLER_KEY); 477 if (data != null) { 478 return data; 479 } 480 } 481 Slog.e(TAG, "no controller energy info supplied for " + receiver.getName()); 482 } catch (TimeoutException e) { 483 Slog.w(TAG, "timeout reading " + receiver.getName() + " stats"); 484 } 485 return null; 486 } 487 488 /** 489 * 490 * Pulls wifi controller activity energy info from WiFiManager 491 */ 492 @Override // Binder call 493 public StatsLogEventWrapper[] pullData(int tagId) { 494 enforceCallingPermission(); 495 if (DEBUG) 496 Slog.d(TAG, "Pulling " + tagId); 497 498 switch (tagId) { 499 case StatsLog.WIFI_BYTES_TRANSFER: { 500 long token = Binder.clearCallingIdentity(); 501 try { 502 // TODO: Consider caching the following call to get BatteryStatsInternal. 503 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); 504 String[] ifaces = bs.getWifiIfaces(); 505 if (ifaces.length == 0) { 506 return null; 507 } 508 NetworkStatsFactory nsf = new NetworkStatsFactory(); 509 // Combine all the metrics per Uid into one record. 510 NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, 511 NetworkStats.TAG_NONE, null).groupedByUid(); 512 return addNetworkStats(tagId, stats, false); 513 } catch (java.io.IOException e) { 514 Slog.e(TAG, "Pulling netstats for wifi bytes has error", e); 515 } finally { 516 Binder.restoreCallingIdentity(token); 517 } 518 break; 519 } 520 case StatsLog.MOBILE_BYTES_TRANSFER: { 521 long token = Binder.clearCallingIdentity(); 522 try { 523 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); 524 String[] ifaces = bs.getMobileIfaces(); 525 if (ifaces.length == 0) { 526 return null; 527 } 528 NetworkStatsFactory nsf = new NetworkStatsFactory(); 529 // Combine all the metrics per Uid into one record. 530 NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, 531 NetworkStats.TAG_NONE, null).groupedByUid(); 532 return addNetworkStats(tagId, stats, false); 533 } catch (java.io.IOException e) { 534 Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); 535 } finally { 536 Binder.restoreCallingIdentity(token); 537 } 538 break; 539 } 540 case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: { 541 long token = Binder.clearCallingIdentity(); 542 try { 543 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); 544 String[] ifaces = bs.getWifiIfaces(); 545 if (ifaces.length == 0) { 546 return null; 547 } 548 NetworkStatsFactory nsf = new NetworkStatsFactory(); 549 NetworkStats stats = rollupNetworkStatsByFGBG( 550 nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, 551 NetworkStats.TAG_NONE, null)); 552 return addNetworkStats(tagId, stats, true); 553 } catch (java.io.IOException e) { 554 Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); 555 } finally { 556 Binder.restoreCallingIdentity(token); 557 } 558 break; 559 } 560 case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: { 561 long token = Binder.clearCallingIdentity(); 562 try { 563 BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class); 564 String[] ifaces = bs.getMobileIfaces(); 565 if (ifaces.length == 0) { 566 return null; 567 } 568 NetworkStatsFactory nsf = new NetworkStatsFactory(); 569 NetworkStats stats = rollupNetworkStatsByFGBG( 570 nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, 571 NetworkStats.TAG_NONE, null)); 572 return addNetworkStats(tagId, stats, true); 573 } catch (java.io.IOException e) { 574 Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); 575 } finally { 576 Binder.restoreCallingIdentity(token); 577 } 578 break; 579 } 580 case StatsLog.KERNEL_WAKELOCK: { 581 final KernelWakelockStats wakelockStats = 582 mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats); 583 List<StatsLogEventWrapper> ret = new ArrayList(); 584 for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) { 585 String name = ent.getKey(); 586 KernelWakelockStats.Entry kws = ent.getValue(); 587 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4); 588 e.writeString(name); 589 e.writeInt(kws.mCount); 590 e.writeInt(kws.mVersion); 591 e.writeLong(kws.mTotalTime); 592 ret.add(e); 593 } 594 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 595 } 596 case StatsLog.CPU_TIME_PER_FREQ: { 597 List<StatsLogEventWrapper> ret = new ArrayList(); 598 for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) { 599 long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute(); 600 if (clusterTimeMs != null) { 601 for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) { 602 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3); 603 e.writeInt(cluster); 604 e.writeInt(speed); 605 e.writeLong(clusterTimeMs[speed]); 606 ret.add(e); 607 } 608 } 609 } 610 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 611 } 612 case StatsLog.WIFI_ACTIVITY_ENERGY_INFO: { 613 List<StatsLogEventWrapper> ret = new ArrayList(); 614 long token = Binder.clearCallingIdentity(); 615 if (mWifiManager == null) { 616 mWifiManager = IWifiManager.Stub.asInterface(ServiceManager.getService( 617 Context.WIFI_SERVICE)); 618 } 619 if (mWifiManager != null) { 620 try { 621 SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi"); 622 mWifiManager.requestActivityInfo(wifiReceiver); 623 final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver); 624 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6); 625 e.writeLong(wifiInfo.getTimeStamp()); 626 e.writeInt(wifiInfo.getStackState()); 627 e.writeLong(wifiInfo.getControllerTxTimeMillis()); 628 e.writeLong(wifiInfo.getControllerRxTimeMillis()); 629 e.writeLong(wifiInfo.getControllerIdleTimeMillis()); 630 e.writeLong(wifiInfo.getControllerEnergyUsed()); 631 ret.add(e); 632 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 633 } catch (RemoteException e) { 634 Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e); 635 } finally { 636 Binder.restoreCallingIdentity(token); 637 } 638 } 639 break; 640 } 641 case StatsLog.MODEM_ACTIVITY_INFO: { 642 List<StatsLogEventWrapper> ret = new ArrayList(); 643 long token = Binder.clearCallingIdentity(); 644 if (mTelephony == null) { 645 mTelephony = TelephonyManager.from(mContext); 646 } 647 if (mTelephony != null) { 648 SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony"); 649 mTelephony.requestModemActivityInfo(modemReceiver); 650 final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver); 651 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6); 652 e.writeLong(modemInfo.getTimestamp()); 653 e.writeLong(modemInfo.getSleepTimeMillis()); 654 e.writeLong(modemInfo.getIdleTimeMillis()); 655 e.writeLong(modemInfo.getTxTimeMillis()[0]); 656 e.writeLong(modemInfo.getTxTimeMillis()[1]); 657 e.writeLong(modemInfo.getTxTimeMillis()[2]); 658 e.writeLong(modemInfo.getTxTimeMillis()[3]); 659 e.writeLong(modemInfo.getTxTimeMillis()[4]); 660 e.writeLong(modemInfo.getRxTimeMillis()); 661 e.writeLong(modemInfo.getEnergyUsed()); 662 ret.add(e); 663 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 664 } 665 break; 666 } 667 case StatsLog.CPU_SUSPEND_TIME: { 668 List<StatsLogEventWrapper> ret = new ArrayList(); 669 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1); 670 e.writeLong(SystemClock.elapsedRealtime()); 671 ret.add(e); 672 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 673 } 674 case StatsLog.CPU_IDLE_TIME: { 675 List<StatsLogEventWrapper> ret = new ArrayList(); 676 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1); 677 e.writeLong(SystemClock.uptimeMillis()); 678 ret.add(e); 679 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 680 } 681 case StatsLog.DISK_SPACE: { 682 List<StatsLogEventWrapper> ret = new ArrayList(); 683 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3); 684 e.writeLong(mStatFsData.getAvailableBytes()); 685 e.writeLong(mStatFsSystem.getAvailableBytes()); 686 e.writeLong(mStatFsTemp.getAvailableBytes()); 687 ret.add(e); 688 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 689 } 690 case StatsLog.SYSTEM_UPTIME: { 691 List<StatsLogEventWrapper> ret = new ArrayList(); 692 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1); 693 e.writeLong(SystemClock.uptimeMillis()); 694 ret.add(e); 695 return ret.toArray(new StatsLogEventWrapper[ret.size()]); 696 } 697 default: 698 Slog.w(TAG, "No such tagId data as " + tagId); 699 return null; 700 } 701 return null; 702 } 703 704 @Override // Binder call 705 public void statsdReady() { 706 enforceCallingPermission(); 707 if (DEBUG) Slog.d(TAG, "learned that statsdReady"); 708 sayHiToStatsd(); // tell statsd that we're ready too and link to it 709 mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED), 710 UserHandle.SYSTEM, 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