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