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