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