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