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 */ 16 package com.android.server.stats; 17 18 import static android.os.Process.THREAD_PRIORITY_BACKGROUND; 19 20 import android.app.AlarmManager; 21 import android.app.AlarmManager.OnAlarmListener; 22 import android.app.StatsManager; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.pm.PackageInfo; 29 import android.content.pm.PackageManager; 30 import android.content.pm.ResolveInfo; 31 import android.os.Binder; 32 import android.os.Bundle; 33 import android.os.FileUtils; 34 import android.os.Handler; 35 import android.os.HandlerThread; 36 import android.os.IBinder; 37 import android.os.IStatsCompanionService; 38 import android.os.IStatsd; 39 import android.os.Looper; 40 import android.os.ParcelFileDescriptor; 41 import android.os.PowerManager; 42 import android.os.RemoteException; 43 import android.os.StatsFrameworkInitializer; 44 import android.os.SystemClock; 45 import android.os.UserHandle; 46 import android.os.UserManager; 47 import android.util.Log; 48 import android.util.proto.ProtoOutputStream; 49 50 import com.android.internal.annotations.GuardedBy; 51 52 import java.io.File; 53 import java.io.FileDescriptor; 54 import java.io.FileOutputStream; 55 import java.io.IOException; 56 import java.io.PrintWriter; 57 import java.util.HashMap; 58 import java.util.HashSet; 59 import java.util.List; 60 import java.util.concurrent.TimeUnit; 61 import java.util.concurrent.atomic.AtomicBoolean; 62 63 /** 64 * Helper service for statsd (the native stats management service in cmds/statsd/). 65 * Used for registering and receiving alarms on behalf of statsd. 66 * 67 * @hide 68 */ 69 public class StatsCompanionService extends IStatsCompanionService.Stub { 70 71 private static final long MILLIS_IN_A_DAY = TimeUnit.DAYS.toMillis(1); 72 73 public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity"; 74 public static final String CONFIG_DIR = "/data/misc/stats-service"; 75 76 static final String TAG = "StatsCompanionService"; 77 static final boolean DEBUG = false; 78 /** 79 * Hard coded field ids of frameworks/base/cmds/statsd/src/uid_data.proto 80 * to be used in ProtoOutputStream. 81 */ 82 private static final int APPLICATION_INFO_FIELD_ID = 1; 83 private static final int UID_FIELD_ID = 1; 84 private static final int VERSION_FIELD_ID = 2; 85 private static final int VERSION_STRING_FIELD_ID = 3; 86 private static final int PACKAGE_NAME_FIELD_ID = 4; 87 private static final int INSTALLER_FIELD_ID = 5; 88 89 public static final int DEATH_THRESHOLD = 10; 90 91 static final class CompanionHandler extends Handler { CompanionHandler(Looper looper)92 CompanionHandler(Looper looper) { 93 super(looper); 94 } 95 } 96 97 private final Context mContext; 98 private final AlarmManager mAlarmManager; 99 @GuardedBy("sStatsdLock") 100 private static IStatsd sStatsd; 101 private static final Object sStatsdLock = new Object(); 102 103 private final OnAlarmListener mAnomalyAlarmListener; 104 private final OnAlarmListener mPullingAlarmListener; 105 private final OnAlarmListener mPeriodicAlarmListener; 106 107 private StatsManagerService mStatsManagerService; 108 109 @GuardedBy("sStatsdLock") 110 private final HashSet<Long> mDeathTimeMillis = new HashSet<>(); 111 @GuardedBy("sStatsdLock") 112 private final HashMap<Long, String> mDeletedFiles = new HashMap<>(); 113 private final CompanionHandler mHandler; 114 115 // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle. 116 private AtomicBoolean mBootCompleted = new AtomicBoolean(false); 117 StatsCompanionService(Context context)118 public StatsCompanionService(Context context) { 119 super(); 120 mContext = context; 121 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 122 if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED."); 123 HandlerThread handlerThread = new HandlerThread(TAG); 124 handlerThread.start(); 125 mHandler = new CompanionHandler(handlerThread.getLooper()); 126 127 mAnomalyAlarmListener = new AnomalyAlarmListener(context); 128 mPullingAlarmListener = new PullingAlarmListener(context); 129 mPeriodicAlarmListener = new PeriodicAlarmListener(context); 130 } 131 toIntArray(List<Integer> list)132 private final static int[] toIntArray(List<Integer> list) { 133 int[] ret = new int[list.size()]; 134 for (int i = 0; i < ret.length; i++) { 135 ret[i] = list.get(i); 136 } 137 return ret; 138 } 139 toLongArray(List<Long> list)140 private final static long[] toLongArray(List<Long> list) { 141 long[] ret = new long[list.size()]; 142 for (int i = 0; i < ret.length; i++) { 143 ret[i] = list.get(i); 144 } 145 return ret; 146 } 147 148 /** 149 * Non-blocking call to retrieve a reference to statsd 150 * 151 * @return IStatsd object if statsd is ready, null otherwise. 152 */ getStatsdNonblocking()153 private static IStatsd getStatsdNonblocking() { 154 synchronized (sStatsdLock) { 155 return sStatsd; 156 } 157 } 158 informAllUids(Context context)159 private static void informAllUids(Context context) { 160 ParcelFileDescriptor[] fds; 161 try { 162 fds = ParcelFileDescriptor.createPipe(); 163 } catch (IOException e) { 164 Log.e(TAG, "Failed to create a pipe to send uid map data.", e); 165 return; 166 } 167 HandlerThread backgroundThread = new HandlerThread( 168 "statsCompanionService.bg", THREAD_PRIORITY_BACKGROUND); 169 backgroundThread.start(); 170 Handler handler = new Handler(backgroundThread.getLooper()); 171 handler.post(() -> { 172 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 173 PackageManager pm = context.getPackageManager(); 174 final List<UserHandle> users = um.getUserHandles(true); 175 if (DEBUG) { 176 Log.d(TAG, "Iterating over " + users.size() + " userHandles."); 177 } 178 IStatsd statsd = getStatsdNonblocking(); 179 if (statsd == null) { 180 return; 181 } 182 try { 183 statsd.informAllUidData(fds[0]); 184 } catch (RemoteException e) { 185 Log.e(TAG, "Failed to send uid map to statsd"); 186 } 187 try { 188 fds[0].close(); 189 } catch (IOException e) { 190 Log.e(TAG, "Failed to close the read side of the pipe.", e); 191 } 192 final ParcelFileDescriptor writeFd = fds[1]; 193 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(writeFd); 194 try { 195 ProtoOutputStream output = new ProtoOutputStream(fout); 196 int numRecords = 0; 197 // Add in all the apps for every user/profile. 198 for (UserHandle userHandle : users) { 199 List<PackageInfo> pi = 200 pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES 201 | PackageManager.MATCH_ANY_USER 202 | PackageManager.MATCH_APEX, 203 userHandle.getIdentifier()); 204 for (int j = 0; j < pi.size(); j++) { 205 if (pi.get(j).applicationInfo != null) { 206 String installer; 207 try { 208 installer = pm.getInstallerPackageName(pi.get(j).packageName); 209 } catch (IllegalArgumentException e) { 210 installer = ""; 211 } 212 long applicationInfoToken = 213 output.start(ProtoOutputStream.FIELD_TYPE_MESSAGE 214 | ProtoOutputStream.FIELD_COUNT_REPEATED 215 | APPLICATION_INFO_FIELD_ID); 216 output.write(ProtoOutputStream.FIELD_TYPE_INT32 217 | ProtoOutputStream.FIELD_COUNT_SINGLE | UID_FIELD_ID, 218 pi.get(j).applicationInfo.uid); 219 output.write(ProtoOutputStream.FIELD_TYPE_INT64 220 | ProtoOutputStream.FIELD_COUNT_SINGLE 221 | VERSION_FIELD_ID, pi.get(j).getLongVersionCode()); 222 output.write(ProtoOutputStream.FIELD_TYPE_STRING 223 | ProtoOutputStream.FIELD_COUNT_SINGLE 224 | VERSION_STRING_FIELD_ID, 225 pi.get(j).versionName); 226 output.write(ProtoOutputStream.FIELD_TYPE_STRING 227 | ProtoOutputStream.FIELD_COUNT_SINGLE 228 | PACKAGE_NAME_FIELD_ID, pi.get(j).packageName); 229 output.write(ProtoOutputStream.FIELD_TYPE_STRING 230 | ProtoOutputStream.FIELD_COUNT_SINGLE 231 | INSTALLER_FIELD_ID, 232 installer == null ? "" : installer); 233 numRecords++; 234 output.end(applicationInfoToken); 235 } 236 } 237 } 238 output.flush(); 239 if (DEBUG) { 240 Log.d(TAG, "Sent data for " + numRecords + " apps"); 241 } 242 } finally { 243 FileUtils.closeQuietly(fout); 244 backgroundThread.quit(); 245 backgroundThread.interrupt(); 246 } 247 }); 248 } 249 250 private static class WakelockThread extends Thread { 251 private final PowerManager.WakeLock mWl; 252 private final Runnable mRunnable; 253 WakelockThread(Context context, String wakelockName, Runnable runnable)254 WakelockThread(Context context, String wakelockName, Runnable runnable) { 255 PowerManager powerManager = (PowerManager) 256 context.getSystemService(Context.POWER_SERVICE); 257 mWl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakelockName); 258 mRunnable = runnable; 259 } 260 @Override run()261 public void run() { 262 try { 263 mRunnable.run(); 264 } finally { 265 mWl.release(); 266 } 267 } 268 @Override start()269 public void start() { 270 mWl.acquire(); 271 super.start(); 272 } 273 } 274 275 private final static class AppUpdateReceiver extends BroadcastReceiver { 276 @Override onReceive(Context context, Intent intent)277 public void onReceive(Context context, Intent intent) { 278 /** 279 * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid 280 * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag. 281 * If we can't find the value for EXTRA_REPLACING, we default to false. 282 */ 283 if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) 284 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 285 return; // Keep only replacing or normal add and remove. 286 } 287 if (DEBUG) Log.d(TAG, "StatsCompanionService noticed an app was updated."); 288 synchronized (sStatsdLock) { 289 if (sStatsd == null) { 290 Log.w(TAG, "Could not access statsd to inform it of an app update"); 291 return; 292 } 293 try { 294 if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { 295 Bundle b = intent.getExtras(); 296 int uid = b.getInt(Intent.EXTRA_UID); 297 boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 298 if (!replacing) { 299 // Don't bother sending an update if we're right about to get another 300 // intent for the new version that's added. 301 String app = intent.getData().getSchemeSpecificPart(); 302 sStatsd.informOnePackageRemoved(app, uid); 303 } 304 } else { 305 PackageManager pm = context.getPackageManager(); 306 Bundle b = intent.getExtras(); 307 int uid = b.getInt(Intent.EXTRA_UID); 308 String app = intent.getData().getSchemeSpecificPart(); 309 PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER); 310 String installer; 311 try { 312 installer = pm.getInstallerPackageName(app); 313 } catch (IllegalArgumentException e) { 314 installer = ""; 315 } 316 sStatsd.informOnePackage( 317 app, 318 uid, 319 pi.getLongVersionCode(), 320 pi.versionName == null ? "" : pi.versionName, 321 installer == null ? "" : installer); 322 } 323 } catch (Exception e) { 324 Log.w(TAG, "Failed to inform statsd of an app update", e); 325 } 326 } 327 } 328 } 329 330 private static final class UserUpdateReceiver extends BroadcastReceiver { 331 @Override onReceive(Context context, Intent intent)332 public void onReceive(Context context, Intent intent) { 333 // Pull the latest state of UID->app name, version mapping. 334 // Needed since the new user basically has a version of every app. 335 informAllUids(context); 336 } 337 } 338 339 public static final class AnomalyAlarmListener implements OnAlarmListener { 340 private final Context mContext; 341 AnomalyAlarmListener(Context context)342 AnomalyAlarmListener(Context context) { 343 mContext = context; 344 } 345 346 @Override onAlarm()347 public void onAlarm() { 348 if (DEBUG) { 349 Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time " 350 + System.currentTimeMillis() + "ms."); 351 } 352 IStatsd statsd = getStatsdNonblocking(); 353 if (statsd == null) { 354 Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); 355 return; 356 } 357 358 // Wakelock needs to be retained while calling statsd. 359 Thread thread = new WakelockThread(mContext, 360 AnomalyAlarmListener.class.getCanonicalName(), new Runnable() { 361 @Override 362 public void run() { 363 try { 364 statsd.informAnomalyAlarmFired(); 365 } catch (RemoteException e) { 366 Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e); 367 } 368 } 369 }); 370 thread.start(); 371 } 372 } 373 374 public final static class PullingAlarmListener implements OnAlarmListener { 375 private final Context mContext; 376 PullingAlarmListener(Context context)377 PullingAlarmListener(Context context) { 378 mContext = context; 379 } 380 381 @Override onAlarm()382 public void onAlarm() { 383 if (DEBUG) { 384 Log.d(TAG, "Time to poll something."); 385 } 386 IStatsd statsd = getStatsdNonblocking(); 387 if (statsd == null) { 388 Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing."); 389 return; 390 } 391 392 // Wakelock needs to be retained while calling statsd. 393 Thread thread = new WakelockThread(mContext, 394 PullingAlarmListener.class.getCanonicalName(), new Runnable() { 395 @Override 396 public void run() { 397 try { 398 statsd.informPollAlarmFired(); 399 } catch (RemoteException e) { 400 Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e); 401 } 402 } 403 }); 404 thread.start(); 405 } 406 } 407 408 public final static class PeriodicAlarmListener implements OnAlarmListener { 409 private final Context mContext; 410 PeriodicAlarmListener(Context context)411 PeriodicAlarmListener(Context context) { 412 mContext = context; 413 } 414 415 @Override onAlarm()416 public void onAlarm() { 417 if (DEBUG) { 418 Log.d(TAG, "Time to trigger periodic alarm."); 419 } 420 IStatsd statsd = getStatsdNonblocking(); 421 if (statsd == null) { 422 Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing."); 423 return; 424 } 425 426 // Wakelock needs to be retained while calling statsd. 427 Thread thread = new WakelockThread(mContext, 428 PeriodicAlarmListener.class.getCanonicalName(), new Runnable() { 429 @Override 430 public void run() { 431 try { 432 statsd.informAlarmForSubscriberTriggeringFired(); 433 } catch (RemoteException e) { 434 Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e); 435 } 436 } 437 }); 438 thread.start(); 439 } 440 } 441 442 public final static class ShutdownEventReceiver extends BroadcastReceiver { 443 @Override onReceive(Context context, Intent intent)444 public void onReceive(Context context, Intent intent) { 445 /** 446 * Skip immediately if intent is not relevant to device shutdown. 447 */ 448 if (!intent.getAction().equals(Intent.ACTION_REBOOT) 449 && !(intent.getAction().equals(Intent.ACTION_SHUTDOWN) 450 && (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0)) { 451 return; 452 } 453 454 if (DEBUG) { 455 Log.i(TAG, "StatsCompanionService noticed a shutdown."); 456 } 457 IStatsd statsd = getStatsdNonblocking(); 458 if (statsd == null) { 459 Log.w(TAG, "Could not access statsd to inform it of a shutdown event."); 460 return; 461 } 462 try { 463 // two way binder call 464 statsd.informDeviceShutdown(); 465 } catch (Exception e) { 466 Log.w(TAG, "Failed to inform statsd of a shutdown event.", e); 467 } 468 } 469 } 470 471 @Override // Binder call setAnomalyAlarm(long timestampMs)472 public void setAnomalyAlarm(long timestampMs) { 473 StatsCompanion.enforceStatsdCallingUid(); 474 if (DEBUG) Log.d(TAG, "Setting anomaly alarm for " + timestampMs); 475 final long callingToken = Binder.clearCallingIdentity(); 476 try { 477 // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will 478 // only fire when it awakens. 479 // AlarmManager will automatically cancel any previous mAnomalyAlarmListener alarm. 480 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".anomaly", 481 mAnomalyAlarmListener, mHandler); 482 } finally { 483 Binder.restoreCallingIdentity(callingToken); 484 } 485 } 486 487 @Override // Binder call cancelAnomalyAlarm()488 public void cancelAnomalyAlarm() { 489 StatsCompanion.enforceStatsdCallingUid(); 490 if (DEBUG) Log.d(TAG, "Cancelling anomaly alarm"); 491 final long callingToken = Binder.clearCallingIdentity(); 492 try { 493 mAlarmManager.cancel(mAnomalyAlarmListener); 494 } finally { 495 Binder.restoreCallingIdentity(callingToken); 496 } 497 } 498 499 @Override // Binder call setAlarmForSubscriberTriggering(long timestampMs)500 public void setAlarmForSubscriberTriggering(long timestampMs) { 501 StatsCompanion.enforceStatsdCallingUid(); 502 if (DEBUG) { 503 Log.d(TAG, 504 "Setting periodic alarm in about " + (timestampMs 505 - SystemClock.elapsedRealtime())); 506 } 507 final long callingToken = Binder.clearCallingIdentity(); 508 try { 509 // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will 510 // only fire when it awakens. 511 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".periodic", 512 mPeriodicAlarmListener, mHandler); 513 } finally { 514 Binder.restoreCallingIdentity(callingToken); 515 } 516 } 517 518 @Override // Binder call cancelAlarmForSubscriberTriggering()519 public void cancelAlarmForSubscriberTriggering() { 520 StatsCompanion.enforceStatsdCallingUid(); 521 if (DEBUG) { 522 Log.d(TAG, "Cancelling periodic alarm"); 523 } 524 final long callingToken = Binder.clearCallingIdentity(); 525 try { 526 mAlarmManager.cancel(mPeriodicAlarmListener); 527 } finally { 528 Binder.restoreCallingIdentity(callingToken); 529 } 530 } 531 532 @Override // Binder call setPullingAlarm(long nextPullTimeMs)533 public void setPullingAlarm(long nextPullTimeMs) { 534 StatsCompanion.enforceStatsdCallingUid(); 535 if (DEBUG) { 536 Log.d(TAG, "Setting pulling alarm in about " 537 + (nextPullTimeMs - SystemClock.elapsedRealtime())); 538 } 539 final long callingToken = Binder.clearCallingIdentity(); 540 try { 541 // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will 542 // only fire when it awakens. 543 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, TAG + ".pull", 544 mPullingAlarmListener, mHandler); 545 } finally { 546 Binder.restoreCallingIdentity(callingToken); 547 } 548 } 549 550 @Override // Binder call cancelPullingAlarm()551 public void cancelPullingAlarm() { 552 StatsCompanion.enforceStatsdCallingUid(); 553 if (DEBUG) { 554 Log.d(TAG, "Cancelling pulling alarm"); 555 } 556 final long callingToken = Binder.clearCallingIdentity(); 557 try { 558 mAlarmManager.cancel(mPullingAlarmListener); 559 } finally { 560 Binder.restoreCallingIdentity(callingToken); 561 } 562 } 563 564 @Override // Binder call statsdReady()565 public void statsdReady() { 566 StatsCompanion.enforceStatsdCallingUid(); 567 if (DEBUG) { 568 Log.d(TAG, "learned that statsdReady"); 569 } 570 sayHiToStatsd(); // tell statsd that we're ready too and link to it 571 572 final Intent intent = new Intent(StatsManager.ACTION_STATSD_STARTED); 573 // Retrieve list of broadcast receivers for this broadcast & send them directed broadcasts 574 // to wake them up (if they're in background). 575 List<ResolveInfo> resolveInfos = 576 mContext.getPackageManager().queryBroadcastReceiversAsUser( 577 intent, 0, UserHandle.SYSTEM); 578 if (resolveInfos == null || resolveInfos.isEmpty()) { 579 return; // No need to send broadcast. 580 } 581 582 for (ResolveInfo resolveInfo : resolveInfos) { 583 Intent intentToSend = new Intent(intent); 584 intentToSend.setComponent(new ComponentName( 585 resolveInfo.activityInfo.applicationInfo.packageName, 586 resolveInfo.activityInfo.name)); 587 mContext.sendBroadcastAsUser(intentToSend, UserHandle.SYSTEM, 588 android.Manifest.permission.DUMP); 589 } 590 } 591 592 @Override // Binder call checkPermission(String permission, int pid, int uid)593 public boolean checkPermission(String permission, int pid, int uid) { 594 StatsCompanion.enforceStatsdCallingUid(); 595 return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED; 596 } 597 598 // Statsd related code 599 600 /** 601 * Fetches the statsd IBinder service. This is a blocking call that always refetches statsd 602 * instead of returning the cached sStatsd. 603 * Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use 604 * the cached sStatsd via {@link #getStatsdNonblocking()}. 605 */ fetchStatsdServiceLocked()606 private IStatsd fetchStatsdServiceLocked() { 607 sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer 608 .getStatsServiceManager() 609 .getStatsdServiceRegisterer() 610 .get()); 611 return sStatsd; 612 } 613 registerStatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers)614 private void registerStatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) { 615 StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient(statsd, receivers); 616 617 try { 618 statsd.asBinder().linkToDeath(deathRecipient, /*flags=*/0); 619 } catch (RemoteException e) { 620 Log.e(TAG, "linkToDeath (StatsdDeathRecipient) failed"); 621 // Statsd has already died. Unregister receivers ourselves. 622 for (BroadcastReceiver receiver : receivers) { 623 mContext.unregisterReceiver(receiver); 624 } 625 synchronized (sStatsdLock) { 626 if (statsd == sStatsd) { 627 statsdNotReadyLocked(); 628 } 629 } 630 } 631 } 632 633 /** 634 * Now that the android system is ready, StatsCompanion is ready too, so inform statsd. 635 */ systemReady()636 void systemReady() { 637 if (DEBUG) Log.d(TAG, "Learned that systemReady"); 638 sayHiToStatsd(); 639 } 640 setStatsManagerService(StatsManagerService statsManagerService)641 void setStatsManagerService(StatsManagerService statsManagerService) { 642 mStatsManagerService = statsManagerService; 643 } 644 645 /** 646 * Tells statsd that statscompanion is ready. If the binder call returns, link to 647 * statsd. 648 */ sayHiToStatsd()649 private void sayHiToStatsd() { 650 IStatsd statsd; 651 synchronized (sStatsdLock) { 652 if (sStatsd != null && sStatsd.asBinder().isBinderAlive()) { 653 Log.e(TAG, "statsd has already been fetched before", 654 new IllegalStateException("IStatsd object should be null or dead")); 655 return; 656 } 657 statsd = fetchStatsdServiceLocked(); 658 } 659 660 if (statsd == null) { 661 Log.i(TAG, "Could not yet find statsd to tell it that StatsCompanion is alive."); 662 return; 663 } 664 665 // Cleann up from previous statsd - cancel any alarms that had been set. Do this here 666 // instead of in binder death because statsd can come back and set different alarms, or not 667 // want to set an alarm when it had been set. This guarantees that when we get a new statsd, 668 // we cancel any alarms before it is able to set them. 669 cancelAnomalyAlarm(); 670 cancelPullingAlarm(); 671 cancelAlarmForSubscriberTriggering(); 672 673 if (DEBUG) Log.d(TAG, "Saying hi to statsd"); 674 mStatsManagerService.statsdReady(statsd); 675 try { 676 statsd.statsCompanionReady(); 677 678 BroadcastReceiver appUpdateReceiver = new AppUpdateReceiver(); 679 BroadcastReceiver userUpdateReceiver = new UserUpdateReceiver(); 680 BroadcastReceiver shutdownEventReceiver = new ShutdownEventReceiver(); 681 682 // Setup broadcast receiver for updates. 683 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED); 684 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 685 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 686 filter.addDataScheme("package"); 687 mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null); 688 689 // Setup receiver for user initialize (which happens once for a new user) 690 // and if a user is removed. 691 filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE); 692 filter.addAction(Intent.ACTION_USER_REMOVED); 693 mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null); 694 695 // Setup receiver for device reboots or shutdowns. 696 filter = new IntentFilter(Intent.ACTION_REBOOT); 697 filter.addAction(Intent.ACTION_SHUTDOWN); 698 mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null, null); 699 700 // Register death recipient. 701 List<BroadcastReceiver> broadcastReceivers = 702 List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver); 703 registerStatsdDeathRecipient(statsd, broadcastReceivers); 704 705 // Tell statsd that boot has completed. The signal may have already been sent, but since 706 // the signal-receiving function is idempotent, that's ok. 707 if (mBootCompleted.get()) { 708 statsd.bootCompleted(); 709 } 710 711 // Pull the latest state of UID->app name, version mapping when statsd starts. 712 informAllUids(mContext); 713 714 Log.i(TAG, "Told statsd that StatsCompanionService is alive."); 715 } catch (RemoteException e) { 716 Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e); 717 } 718 } 719 720 private class StatsdDeathRecipient implements IBinder.DeathRecipient { 721 722 private final IStatsd mStatsd; 723 private final List<BroadcastReceiver> mReceiversToUnregister; 724 StatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers)725 StatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) { 726 mStatsd = statsd; 727 mReceiversToUnregister = receivers; 728 } 729 730 // It is possible for binderDied to be called after a restarted statsd calls statsdReady, 731 // but that's alright because the code does not assume an ordering of the two calls. 732 @Override binderDied()733 public void binderDied() { 734 Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers"); 735 synchronized (sStatsdLock) { 736 long now = SystemClock.elapsedRealtime(); 737 for (Long timeMillis : mDeathTimeMillis) { 738 long ageMillis = now - timeMillis; 739 if (ageMillis > MILLIS_IN_A_DAY) { 740 mDeathTimeMillis.remove(timeMillis); 741 } 742 } 743 for (Long timeMillis : mDeletedFiles.keySet()) { 744 long ageMillis = now - timeMillis; 745 if (ageMillis > MILLIS_IN_A_DAY * 7) { 746 mDeletedFiles.remove(timeMillis); 747 } 748 } 749 mDeathTimeMillis.add(now); 750 if (mDeathTimeMillis.size() >= DEATH_THRESHOLD) { 751 mDeathTimeMillis.clear(); 752 File[] configs = new File(CONFIG_DIR).listFiles(); 753 if (configs != null && configs.length > 0) { 754 String fileName = configs[0].getName(); 755 if (configs[0].delete()) { 756 mDeletedFiles.put(now, fileName); 757 } 758 } 759 } 760 761 // Unregister receivers on death because receivers can only be unregistered once. 762 // Otherwise, an IllegalArgumentException is thrown. 763 for (BroadcastReceiver receiver: mReceiversToUnregister) { 764 mContext.unregisterReceiver(receiver); 765 } 766 767 // It's possible for statsd to have restarted and called statsdReady, causing a new 768 // sStatsd binder object to be fetched, before the binderDied callback runs. Only 769 // call #statsdNotReadyLocked if that hasn't happened yet. 770 if (mStatsd == sStatsd) { 771 statsdNotReadyLocked(); 772 } 773 } 774 } 775 } 776 statsdNotReadyLocked()777 private void statsdNotReadyLocked() { 778 sStatsd = null; 779 mStatsManagerService.statsdNotReady(); 780 } 781 bootCompleted()782 void bootCompleted() { 783 mBootCompleted.set(true); 784 IStatsd statsd = getStatsdNonblocking(); 785 if (statsd == null) { 786 // Statsd is not yet ready. 787 // Delay the boot completed ping to {@link #sayHiToStatsd()} 788 return; 789 } 790 try { 791 statsd.bootCompleted(); 792 } catch (RemoteException e) { 793 Log.e(TAG, "Failed to notify statsd that boot completed"); 794 } 795 } 796 797 @Override dump(FileDescriptor fd, PrintWriter writer, String[] args)798 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 799 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 800 != PackageManager.PERMISSION_GRANTED) { 801 return; 802 } 803 804 synchronized (sStatsdLock) { 805 writer.println("Number of configuration files deleted: " + mDeletedFiles.size()); 806 if (mDeletedFiles.size() > 0) { 807 writer.println(" timestamp, deleted file name"); 808 } 809 long lastBootMillis = 810 SystemClock.currentThreadTimeMillis() - SystemClock.elapsedRealtime(); 811 for (Long elapsedMillis : mDeletedFiles.keySet()) { 812 long deletionMillis = lastBootMillis + elapsedMillis; 813 writer.println(" " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis)); 814 } 815 } 816 } 817 } 818