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