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