StatsCompanionService.java revision 2f6f33fa792057b47c0e29ef0b01c091ce2b1068
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 */
16package com.android.server.stats;
17
18import android.annotation.Nullable;
19import android.app.ActivityManagerInternal;
20import android.app.AlarmManager;
21import android.app.PendingIntent;
22import android.app.ProcessMemoryState;
23import android.app.StatsManager;
24import android.bluetooth.BluetoothActivityEnergyInfo;
25import android.bluetooth.BluetoothAdapter;
26import android.bluetooth.UidTraffic;
27import android.content.BroadcastReceiver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.IntentSender;
32import android.content.pm.PackageInfo;
33import android.content.pm.PackageManager;
34import android.content.pm.UserInfo;
35import android.net.NetworkStats;
36import android.net.wifi.IWifiManager;
37import android.net.wifi.WifiActivityEnergyInfo;
38import android.os.BatteryStatsInternal;
39import android.os.Binder;
40import android.os.Bundle;
41import android.os.Environment;
42import android.os.FileUtils;
43import android.os.IBinder;
44import android.os.IStatsCompanionService;
45import android.os.IStatsManager;
46import android.os.Parcelable;
47import android.os.Process;
48import android.os.RemoteException;
49import android.os.ServiceManager;
50import android.os.StatFs;
51import android.os.StatsDimensionsValue;
52import android.os.StatsLogEventWrapper;
53import android.os.SynchronousResultReceiver;
54import android.os.SystemClock;
55import android.os.UserHandle;
56import android.os.UserManager;
57import android.telephony.ModemActivityInfo;
58import android.telephony.TelephonyManager;
59import android.util.Slog;
60import android.util.StatsLog;
61
62import com.android.internal.annotations.GuardedBy;
63import com.android.internal.net.NetworkStatsFactory;
64import com.android.internal.os.KernelCpuSpeedReader;
65import com.android.internal.os.KernelUidCpuTimeReader;
66import com.android.internal.os.KernelUidCpuClusterTimeReader;
67import com.android.internal.os.KernelUidCpuActiveTimeReader;
68import com.android.internal.os.KernelUidCpuFreqTimeReader;
69import com.android.internal.os.KernelWakelockReader;
70import com.android.internal.os.KernelWakelockStats;
71import com.android.internal.os.PowerProfile;
72import com.android.internal.util.DumpUtils;
73import com.android.server.LocalServices;
74import com.android.server.SystemService;
75
76import java.io.File;
77import java.io.FileDescriptor;
78import java.io.IOException;
79import java.io.PrintWriter;
80import java.util.ArrayList;
81import java.util.Arrays;
82import java.util.HashMap;
83import java.util.HashSet;
84import java.util.List;
85import java.util.Map;
86import java.util.concurrent.TimeUnit;
87import java.util.concurrent.TimeoutException;
88
89/**
90 * Helper service for statsd (the native stats management service in cmds/statsd/).
91 * Used for registering and receiving alarms on behalf of statsd.
92 *
93 * @hide
94 */
95public class StatsCompanionService extends IStatsCompanionService.Stub {
96    /**
97     * How long to wait on an individual subsystem to return its stats.
98     */
99    private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000;
100    private static final long MILLIS_IN_A_DAY = TimeUnit.DAYS.toMillis(1);
101
102    public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
103    public static final String CONFIG_DIR = "/data/misc/stats-service";
104
105    static final String TAG = "StatsCompanionService";
106    static final boolean DEBUG = false;
107
108    public static final int CODE_DATA_BROADCAST = 1;
109    public static final int CODE_SUBSCRIBER_BROADCAST = 1;
110    public static final int DEATH_THRESHOLD = 10;
111
112    private final Context mContext;
113    private final AlarmManager mAlarmManager;
114    @GuardedBy("sStatsdLock")
115    private static IStatsManager sStatsd;
116    private static final Object sStatsdLock = new Object();
117
118    private final PendingIntent mAnomalyAlarmIntent;
119    private final PendingIntent mPullingAlarmIntent;
120    private final PendingIntent mPeriodicAlarmIntent;
121    private final BroadcastReceiver mAppUpdateReceiver;
122    private final BroadcastReceiver mUserUpdateReceiver;
123    private final ShutdownEventReceiver mShutdownEventReceiver;
124    private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
125    private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
126    private IWifiManager mWifiManager = null;
127    private TelephonyManager mTelephony = null;
128    private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
129    private final StatFs mStatFsSystem =
130            new StatFs(Environment.getRootDirectory().getAbsolutePath());
131    private final StatFs mStatFsTemp =
132            new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
133    @GuardedBy("sStatsdLock")
134    private final HashSet<Long> mDeathTimeMillis = new HashSet<>();
135    @GuardedBy("sStatsdLock")
136    private final HashMap<Long, String> mDeletedFiles = new HashMap<>();
137
138    private KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
139    private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
140    private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader =
141            new KernelUidCpuFreqTimeReader();
142    private KernelUidCpuActiveTimeReader mKernelUidCpuActiveTimeReader =
143            new KernelUidCpuActiveTimeReader();
144    private KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =
145            new KernelUidCpuClusterTimeReader();
146
147    public StatsCompanionService(Context context) {
148        super();
149        mContext = context;
150        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
151
152        mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
153                new Intent(mContext, AnomalyAlarmReceiver.class), 0);
154        mPullingAlarmIntent = PendingIntent.getBroadcast(
155                mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
156        mPeriodicAlarmIntent = PendingIntent.getBroadcast(
157                mContext, 0, new Intent(mContext, PeriodicAlarmReceiver.class), 0);
158        mAppUpdateReceiver = new AppUpdateReceiver();
159        mUserUpdateReceiver = new BroadcastReceiver() {
160            @Override
161            public void onReceive(Context context, Intent intent) {
162                synchronized (sStatsdLock) {
163                    sStatsd = fetchStatsdService();
164                    if (sStatsd == null) {
165                        Slog.w(TAG, "Could not access statsd for UserUpdateReceiver");
166                        return;
167                    }
168                    try {
169                        // Pull the latest state of UID->app name, version mapping.
170                        // Needed since the new user basically has a version of every app.
171                        informAllUidsLocked(context);
172                    } catch (RemoteException e) {
173                        Slog.e(TAG, "Failed to inform statsd latest update of all apps", e);
174                        forgetEverythingLocked();
175                    }
176                }
177            }
178        };
179        mShutdownEventReceiver = new ShutdownEventReceiver();
180        if (DEBUG) Slog.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
181        PowerProfile powerProfile = new PowerProfile(context);
182        final int numClusters = powerProfile.getNumCpuClusters();
183        mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
184        int firstCpuOfCluster = 0;
185        for (int i = 0; i < numClusters; i++) {
186            final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i);
187            mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
188                    numSpeedSteps);
189            firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i);
190        }
191        // use default throttling in
192        // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
193        mKernelUidCpuFreqTimeReader.setThrottleInterval(0);
194        long[] freqs = mKernelUidCpuFreqTimeReader.readFreqs(powerProfile);
195        mKernelUidCpuClusterTimeReader.setThrottleInterval(0);
196        mKernelUidCpuActiveTimeReader.setThrottleInterval(0);
197    }
198
199    @Override
200    public void sendDataBroadcast(IBinder intentSenderBinder) {
201        enforceCallingPermission();
202        IntentSender intentSender = new IntentSender(intentSenderBinder);
203        Intent intent = new Intent();
204        try {
205            intentSender.sendIntent(mContext, CODE_DATA_BROADCAST, intent, null, null);
206        } catch (IntentSender.SendIntentException e) {
207            Slog.w(TAG, "Unable to send using IntentSender");
208        }
209    }
210
211    @Override
212    public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
213                                        long subscriptionId, long subscriptionRuleId,
214                                        String[] cookies,
215                                        StatsDimensionsValue dimensionsValue) {
216        enforceCallingPermission();
217        IntentSender intentSender = new IntentSender(intentSenderBinder);
218        Intent intent = new Intent()
219                .putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
220                .putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configKey)
221                .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
222                .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId)
223                .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
224
225        ArrayList<String> cookieList = new ArrayList<>(cookies.length);
226        for (String cookie : cookies) { cookieList.add(cookie); }
227        intent.putStringArrayListExtra(
228                StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
229
230        if (DEBUG) {
231            Slog.d(TAG, String.format(
232                    "Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
233                    configUid, configKey, subscriptionId, subscriptionRuleId,
234                    Arrays.toString(cookies), dimensionsValue));
235        }
236        try {
237            intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
238        } catch (IntentSender.SendIntentException e) {
239            Slog.w(TAG, "Unable to send using IntentSender from uid " + configUid
240                    + "; presumably it had been cancelled.");
241        }
242    }
243
244    private final static int[] toIntArray(List<Integer> list) {
245        int[] ret = new int[list.size()];
246        for (int i = 0; i < ret.length; i++) {
247            ret[i] = list.get(i);
248        }
249        return ret;
250    }
251
252    private final static long[] toLongArray(List<Long> list) {
253        long[] ret = new long[list.size()];
254        for (int i = 0; i < ret.length; i++) {
255            ret[i] = list.get(i);
256        }
257        return ret;
258    }
259
260    // Assumes that sStatsdLock is held.
261    @GuardedBy("sStatsdLock")
262    private final void informAllUidsLocked(Context context) throws RemoteException {
263        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
264        PackageManager pm = context.getPackageManager();
265        final List<UserInfo> users = um.getUsers(true);
266        if (DEBUG) {
267            Slog.d(TAG, "Iterating over " + users.size() + " profiles.");
268        }
269
270        List<Integer> uids = new ArrayList<>();
271        List<Long> versions = new ArrayList<>();
272        List<String> apps = new ArrayList<>();
273
274        // Add in all the apps for every user/profile.
275        for (UserInfo profile : users) {
276            List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id);
277            for (int j = 0; j < pi.size(); j++) {
278                if (pi.get(j).applicationInfo != null) {
279                    uids.add(pi.get(j).applicationInfo.uid);
280                    versions.add(pi.get(j).getLongVersionCode());
281                    apps.add(pi.get(j).packageName);
282                }
283            }
284        }
285        sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new
286                String[apps.size()]));
287        if (DEBUG) {
288            Slog.d(TAG, "Sent data for " + uids.size() + " apps");
289        }
290    }
291
292    private final static class AppUpdateReceiver extends BroadcastReceiver {
293        @Override
294        public void onReceive(Context context, Intent intent) {
295            /**
296             * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid
297             * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag.
298             * If we can't find the value for EXTRA_REPLACING, we default to false.
299             */
300            if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)
301                    && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
302                return; // Keep only replacing or normal add and remove.
303            }
304            if (DEBUG) Slog.d(TAG, "StatsCompanionService noticed an app was updated.");
305            synchronized (sStatsdLock) {
306                if (sStatsd == null) {
307                    Slog.w(TAG, "Could not access statsd to inform it of an app update");
308                    return;
309                }
310                try {
311                    if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
312                        Bundle b = intent.getExtras();
313                        int uid = b.getInt(Intent.EXTRA_UID);
314                        boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
315                        if (!replacing) {
316                            // Don't bother sending an update if we're right about to get another
317                            // intent for the new version that's added.
318                            PackageManager pm = context.getPackageManager();
319                            String app = intent.getData().getSchemeSpecificPart();
320                            sStatsd.informOnePackageRemoved(app, uid);
321                        }
322                    } else {
323                        PackageManager pm = context.getPackageManager();
324                        Bundle b = intent.getExtras();
325                        int uid = b.getInt(Intent.EXTRA_UID);
326                        String app = intent.getData().getSchemeSpecificPart();
327                        PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER);
328                        sStatsd.informOnePackage(app, uid, pi.getLongVersionCode());
329                    }
330                } catch (Exception e) {
331                    Slog.w(TAG, "Failed to inform statsd of an app update", e);
332                }
333            }
334        }
335    }
336
337    public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
338        @Override
339        public void onReceive(Context context, Intent intent) {
340            Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
341                    + System.currentTimeMillis() + "ms.");
342            synchronized (sStatsdLock) {
343                if (sStatsd == null) {
344                    Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
345                    return;
346                }
347                try {
348                    // Two-way call to statsd to retain AlarmManager wakelock
349                    sStatsd.informAnomalyAlarmFired();
350                } catch (RemoteException e) {
351                    Slog.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
352                }
353            }
354            // AlarmManager releases its own wakelock here.
355        }
356    }
357
358    public final static class PullingAlarmReceiver extends BroadcastReceiver {
359        @Override
360        public void onReceive(Context context, Intent intent) {
361            if (DEBUG)
362                Slog.d(TAG, "Time to poll something.");
363            synchronized (sStatsdLock) {
364                if (sStatsd == null) {
365                    Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
366                    return;
367                }
368                try {
369                    // Two-way call to statsd to retain AlarmManager wakelock
370                    sStatsd.informPollAlarmFired();
371                } catch (RemoteException e) {
372                    Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
373                }
374            }
375        }
376    }
377
378    public final static class PeriodicAlarmReceiver extends BroadcastReceiver {
379        @Override
380        public void onReceive(Context context, Intent intent) {
381            if (DEBUG)
382                Slog.d(TAG, "Time to poll something.");
383            synchronized (sStatsdLock) {
384                if (sStatsd == null) {
385                    Slog.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
386                    return;
387                }
388                try {
389                    // Two-way call to statsd to retain AlarmManager wakelock
390                    sStatsd.informAlarmForSubscriberTriggeringFired();
391                } catch (RemoteException e) {
392                    Slog.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
393                }
394            }
395            // AlarmManager releases its own wakelock here.
396        }
397    }
398
399    public final static class ShutdownEventReceiver extends BroadcastReceiver {
400        @Override
401        public void onReceive(Context context, Intent intent) {
402            /**
403             * Skip immediately if intent is not relevant to device shutdown.
404             */
405            if (!intent.getAction().equals(Intent.ACTION_REBOOT)
406                    && !(intent.getAction().equals(Intent.ACTION_SHUTDOWN)
407                    && (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0)) {
408                return;
409            }
410
411            Slog.i(TAG, "StatsCompanionService noticed a shutdown.");
412            synchronized (sStatsdLock) {
413                if (sStatsd == null) {
414                    Slog.w(TAG, "Could not access statsd to inform it of a shutdown event.");
415                    return;
416                }
417                try {
418                    sStatsd.writeDataToDisk();
419                } catch (Exception e) {
420                    Slog.w(TAG, "Failed to inform statsd of a shutdown event.", e);
421                }
422            }
423        }
424    }
425
426    @Override // Binder call
427    public void setAnomalyAlarm(long timestampMs) {
428        enforceCallingPermission();
429        if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
430        final long callingToken = Binder.clearCallingIdentity();
431        try {
432            // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
433            // only fire when it awakens.
434            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
435            // AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm.
436            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mAnomalyAlarmIntent);
437        } finally {
438            Binder.restoreCallingIdentity(callingToken);
439        }
440    }
441
442    @Override // Binder call
443    public void cancelAnomalyAlarm() {
444        enforceCallingPermission();
445        if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
446        final long callingToken = Binder.clearCallingIdentity();
447        try {
448            mAlarmManager.cancel(mAnomalyAlarmIntent);
449        } finally {
450            Binder.restoreCallingIdentity(callingToken);
451        }
452    }
453
454    @Override // Binder call
455    public void setAlarmForSubscriberTriggering(long timestampMs) {
456        enforceCallingPermission();
457        if (DEBUG)
458            Slog.d(TAG, "Setting periodic alarm at " + timestampMs);
459        final long callingToken = Binder.clearCallingIdentity();
460        try {
461            // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
462            // only fire when it awakens.
463            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
464            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
465        } finally {
466            Binder.restoreCallingIdentity(callingToken);
467        }
468    }
469
470    @Override // Binder call
471    public void cancelAlarmForSubscriberTriggering() {
472        enforceCallingPermission();
473        if (DEBUG)
474            Slog.d(TAG, "Cancelling periodic alarm");
475        final long callingToken = Binder.clearCallingIdentity();
476        try {
477            mAlarmManager.cancel(mPeriodicAlarmIntent);
478        } finally {
479            Binder.restoreCallingIdentity(callingToken);
480        }
481    }
482
483    @Override // Binder call
484    public void setPullingAlarm(long nextPullTimeMs) {
485      enforceCallingPermission();
486      if (DEBUG)
487        Slog.d(TAG,
488            "Setting pulling alarm in about " + (nextPullTimeMs - SystemClock.elapsedRealtime()));
489      final long callingToken = Binder.clearCallingIdentity();
490      try {
491        // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
492        // only fire when it awakens.
493        mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, mPullingAlarmIntent);
494      } finally {
495        Binder.restoreCallingIdentity(callingToken);
496      }
497    }
498
499    @Override // Binder call
500    public void cancelPullingAlarm() {
501      enforceCallingPermission();
502      if (DEBUG)
503        Slog.d(TAG, "Cancelling pulling alarm");
504      final long callingToken = Binder.clearCallingIdentity();
505      try {
506        mAlarmManager.cancel(mPullingAlarmIntent);
507      } finally {
508        Binder.restoreCallingIdentity(callingToken);
509      }
510    }
511
512    private void addNetworkStats(
513            int tag, List<StatsLogEventWrapper> ret, NetworkStats stats, boolean withFGBG) {
514        int size = stats.size();
515        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
516        NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
517        for (int j = 0; j < size; j++) {
518            stats.getValues(j, entry);
519            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tag, withFGBG ? 6 : 5);
520            e.writeInt(entry.uid);
521            if (withFGBG) {
522                e.writeInt(entry.set);
523            }
524            e.writeLong(entry.rxBytes);
525            e.writeLong(entry.rxPackets);
526            e.writeLong(entry.txBytes);
527            e.writeLong(entry.txPackets);
528            ret.add(e);
529        }
530    }
531
532    /**
533     * Allows rollups per UID but keeping the set (foreground/background) slicing.
534     * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java
535     */
536    private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) {
537        final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1);
538
539        final NetworkStats.Entry entry = new NetworkStats.Entry();
540        entry.iface = NetworkStats.IFACE_ALL;
541        entry.tag = NetworkStats.TAG_NONE;
542        entry.metered = NetworkStats.METERED_ALL;
543        entry.roaming = NetworkStats.ROAMING_ALL;
544
545        int size = stats.size();
546        NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values
547        for (int i = 0; i < size; i++) {
548            stats.getValues(i, recycle);
549
550            // Skip specific tags, since already counted in TAG_NONE
551            if (recycle.tag != NetworkStats.TAG_NONE) continue;
552
553            entry.set = recycle.set; // Allows slicing by background/foreground
554            entry.uid = recycle.uid;
555            entry.rxBytes = recycle.rxBytes;
556            entry.rxPackets = recycle.rxPackets;
557            entry.txBytes = recycle.txBytes;
558            entry.txPackets = recycle.txPackets;
559            // Operations purposefully omitted since we don't use them for statsd.
560            ret.combineValues(entry);
561        }
562        return ret;
563    }
564
565    /**
566     * Helper method to extract the Parcelable controller info from a
567     * SynchronousResultReceiver.
568     */
569    private static <T extends Parcelable> T awaitControllerInfo(
570            @Nullable SynchronousResultReceiver receiver) {
571        if (receiver == null) {
572            return null;
573        }
574
575        try {
576            final SynchronousResultReceiver.Result result =
577                    receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS);
578            if (result.bundle != null) {
579                // This is the final destination for the Bundle.
580                result.bundle.setDefusable(true);
581
582                final T data = result.bundle.getParcelable(
583                        RESULT_RECEIVER_CONTROLLER_KEY);
584                if (data != null) {
585                    return data;
586                }
587            }
588            Slog.e(TAG, "no controller energy info supplied for " + receiver.getName());
589        } catch (TimeoutException e) {
590            Slog.w(TAG, "timeout reading " + receiver.getName() + " stats");
591        }
592        return null;
593    }
594
595    private void pullKernelWakelock(int tagId, List<StatsLogEventWrapper> pulledData) {
596        final KernelWakelockStats wakelockStats =
597                mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
598        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
599        for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
600            String name = ent.getKey();
601            KernelWakelockStats.Entry kws = ent.getValue();
602            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 4);
603            e.writeString(name);
604            e.writeInt(kws.mCount);
605            e.writeInt(kws.mVersion);
606            e.writeLong(kws.mTotalTime);
607            pulledData.add(e);
608        }
609    }
610
611    private void pullWifiBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
612        long token = Binder.clearCallingIdentity();
613        try {
614            // TODO: Consider caching the following call to get BatteryStatsInternal.
615            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
616            String[] ifaces = bs.getWifiIfaces();
617            if (ifaces.length == 0) {
618                return;
619            }
620            NetworkStatsFactory nsf = new NetworkStatsFactory();
621            // Combine all the metrics per Uid into one record.
622            NetworkStats stats =
623                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
624                            .groupedByUid();
625            addNetworkStats(tagId, pulledData, stats, false);
626        } catch (java.io.IOException e) {
627            Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
628        } finally {
629            Binder.restoreCallingIdentity(token);
630        }
631    }
632
633    private void pullWifiBytesTransferByFgBg(int tagId, List<StatsLogEventWrapper> pulledData) {
634        long token = Binder.clearCallingIdentity();
635        try {
636            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
637            String[] ifaces = bs.getWifiIfaces();
638            if (ifaces.length == 0) {
639                return;
640            }
641            NetworkStatsFactory nsf = new NetworkStatsFactory();
642            NetworkStats stats = rollupNetworkStatsByFGBG(
643                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
644            addNetworkStats(tagId, pulledData, stats, true);
645        } catch (java.io.IOException e) {
646            Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
647        } finally {
648            Binder.restoreCallingIdentity(token);
649        }
650    }
651
652    private void pullMobileBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
653        long token = Binder.clearCallingIdentity();
654        try {
655            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
656            String[] ifaces = bs.getMobileIfaces();
657            if (ifaces.length == 0) {
658                return;
659            }
660            NetworkStatsFactory nsf = new NetworkStatsFactory();
661            // Combine all the metrics per Uid into one record.
662            NetworkStats stats =
663                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
664                            .groupedByUid();
665            addNetworkStats(tagId, pulledData, stats, false);
666        } catch (java.io.IOException e) {
667            Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
668        } finally {
669            Binder.restoreCallingIdentity(token);
670        }
671    }
672
673    private void pullBluetoothBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
674        BluetoothActivityEnergyInfo info = pullBluetoothData();
675        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
676        if (info.getUidTraffic() != null) {
677            for (UidTraffic traffic : info.getUidTraffic()) {
678                StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
679                e.writeInt(traffic.getUid());
680                e.writeLong(traffic.getRxBytes());
681                e.writeLong(traffic.getTxBytes());
682                pulledData.add(e);
683            }
684        }
685    }
686
687    private void pullMobileBytesTransferByFgBg(int tagId, List<StatsLogEventWrapper> pulledData) {
688        long token = Binder.clearCallingIdentity();
689        try {
690            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
691            String[] ifaces = bs.getMobileIfaces();
692            if (ifaces.length == 0) {
693                return;
694            }
695            NetworkStatsFactory nsf = new NetworkStatsFactory();
696            NetworkStats stats = rollupNetworkStatsByFGBG(
697                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
698            addNetworkStats(tagId, pulledData, stats, true);
699        } catch (java.io.IOException e) {
700            Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
701        } finally {
702            Binder.restoreCallingIdentity(token);
703        }
704    }
705
706    private void pullCpuTimePerFreq(int tagId, List<StatsLogEventWrapper> pulledData) {
707        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
708        for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
709            long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
710            if (clusterTimeMs != null) {
711                for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
712                    StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
713                    e.writeInt(cluster);
714                    e.writeInt(speed);
715                    e.writeLong(clusterTimeMs[speed]);
716                    pulledData.add(e);
717                }
718            }
719        }
720    }
721
722    private void pullKernelUidCpuTime(int tagId, List<StatsLogEventWrapper> pulledData) {
723        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
724        mKernelUidCpuTimeReader.readAbsolute((uid, userTimeUs, systemTimeUs) -> {
725            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
726            e.writeInt(uid);
727            e.writeLong(userTimeUs);
728            e.writeLong(systemTimeUs);
729            pulledData.add(e);
730        });
731    }
732
733    private void pullKernelUidCpuFreqTime(int tagId, List<StatsLogEventWrapper> pulledData) {
734        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
735        mKernelUidCpuFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
736            for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
737                if(cpuFreqTimeMs[freqIndex] != 0) {
738                    StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
739                    e.writeInt(uid);
740                    e.writeInt(freqIndex);
741                    e.writeLong(cpuFreqTimeMs[freqIndex]);
742                    pulledData.add(e);
743                }
744            }
745        });
746    }
747
748    private void pullKernelUidCpuClusterTime(int tagId, List<StatsLogEventWrapper> pulledData) {
749        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
750        mKernelUidCpuClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> {
751            for (int i = 0; i < cpuClusterTimesMs.length; i++) {
752                StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
753                e.writeInt(uid);
754                e.writeInt(i);
755                e.writeLong(cpuClusterTimesMs[i]);
756                pulledData.add(e);
757            }
758        });
759    }
760
761    private void pullKernelUidCpuActiveTime(int tagId, List<StatsLogEventWrapper> pulledData) {
762        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
763        mKernelUidCpuActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> {
764            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 2);
765            e.writeInt(uid);
766            e.writeLong((long)cpuActiveTimesMs);
767            pulledData.add(e);
768        });
769    }
770
771    private void pullWifiActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
772        long token = Binder.clearCallingIdentity();
773        if (mWifiManager == null) {
774            mWifiManager =
775                    IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE));
776        }
777        if (mWifiManager != null) {
778            try {
779                SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
780                mWifiManager.requestActivityInfo(wifiReceiver);
781                final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
782                StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 6);
783                e.writeLong(wifiInfo.getTimeStamp());
784                e.writeInt(wifiInfo.getStackState());
785                e.writeLong(wifiInfo.getControllerTxTimeMillis());
786                e.writeLong(wifiInfo.getControllerRxTimeMillis());
787                e.writeLong(wifiInfo.getControllerIdleTimeMillis());
788                e.writeLong(wifiInfo.getControllerEnergyUsed());
789                pulledData.add(e);
790            } catch (RemoteException e) {
791                Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e);
792            } finally {
793                Binder.restoreCallingIdentity(token);
794            }
795        }
796    }
797
798    private void pullModemActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
799        long token = Binder.clearCallingIdentity();
800        if (mTelephony == null) {
801            mTelephony = TelephonyManager.from(mContext);
802        }
803        if (mTelephony != null) {
804            SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
805            mTelephony.requestModemActivityInfo(modemReceiver);
806            final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
807            StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 6);
808            e.writeLong(modemInfo.getTimestamp());
809            e.writeLong(modemInfo.getSleepTimeMillis());
810            e.writeLong(modemInfo.getIdleTimeMillis());
811            e.writeLong(modemInfo.getTxTimeMillis()[0]);
812            e.writeLong(modemInfo.getTxTimeMillis()[1]);
813            e.writeLong(modemInfo.getTxTimeMillis()[2]);
814            e.writeLong(modemInfo.getTxTimeMillis()[3]);
815            e.writeLong(modemInfo.getTxTimeMillis()[4]);
816            e.writeLong(modemInfo.getRxTimeMillis());
817            e.writeLong(modemInfo.getEnergyUsed());
818            pulledData.add(e);
819        }
820    }
821
822    private void pullBluetoothActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
823        BluetoothActivityEnergyInfo info = pullBluetoothData();
824        StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 6);
825        e.writeLong(info.getTimeStamp());
826        e.writeInt(info.getBluetoothStackState());
827        e.writeLong(info.getControllerTxTimeMillis());
828        e.writeLong(info.getControllerRxTimeMillis());
829        e.writeLong(info.getControllerIdleTimeMillis());
830        e.writeLong(info.getControllerEnergyUsed());
831        pulledData.add(e);
832    }
833
834    private synchronized BluetoothActivityEnergyInfo pullBluetoothData() {
835        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
836        if (adapter != null) {
837            SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
838            adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
839            return awaitControllerInfo(bluetoothReceiver);
840        } else {
841            Slog.e(TAG, "Failed to get bluetooth adapter!");
842            return null;
843        }
844    }
845
846    private void pullSystemElapsedRealtime(int tagId, List<StatsLogEventWrapper> pulledData) {
847        StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 1);
848        e.writeLong(SystemClock.elapsedRealtime());
849        pulledData.add(e);
850    }
851
852    private void pullDiskSpace(int tagId, List<StatsLogEventWrapper> pulledData) {
853        StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 3);
854        e.writeLong(mStatFsData.getAvailableBytes());
855        e.writeLong(mStatFsSystem.getAvailableBytes());
856        e.writeLong(mStatFsTemp.getAvailableBytes());
857        pulledData.add(e);
858    }
859
860    private void pullSystemUpTime(int tagId, List<StatsLogEventWrapper> pulledData) {
861        StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 1);
862        e.writeLong(SystemClock.uptimeMillis());
863        pulledData.add(e);
864    }
865
866    private void pullProcessMemoryState(int tagId, List<StatsLogEventWrapper> pulledData) {
867        List<ProcessMemoryState> processMemoryStates =
868                LocalServices.getService(ActivityManagerInternal.class)
869                        .getMemoryStateForProcesses();
870        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
871        for (ProcessMemoryState processMemoryState : processMemoryStates) {
872            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 8 /* fields */);
873            e.writeInt(processMemoryState.uid);
874            e.writeString(processMemoryState.processName);
875            e.writeInt(processMemoryState.oomScore);
876            e.writeLong(processMemoryState.pgfault);
877            e.writeLong(processMemoryState.pgmajfault);
878            e.writeLong(processMemoryState.rssInBytes);
879            e.writeLong(processMemoryState.cacheInBytes);
880            e.writeLong(processMemoryState.swapInBytes);
881            pulledData.add(e);
882        }
883    }
884
885    /**
886     * Pulls various data.
887     */
888    @Override // Binder call
889    public StatsLogEventWrapper[] pullData(int tagId) {
890        enforceCallingPermission();
891        if (DEBUG)
892            Slog.d(TAG, "Pulling " + tagId);
893        List<StatsLogEventWrapper> ret = new ArrayList<>();
894        switch (tagId) {
895            case StatsLog.WIFI_BYTES_TRANSFER: {
896                pullWifiBytesTransfer(tagId, ret);
897                break;
898            }
899            case StatsLog.MOBILE_BYTES_TRANSFER: {
900                pullMobileBytesTransfer(tagId, ret);
901                break;
902            }
903            case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
904                pullWifiBytesTransferByFgBg(tagId, ret);
905                break;
906            }
907            case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
908                pullMobileBytesTransferByFgBg(tagId, ret);
909                break;
910            }
911            case StatsLog.BLUETOOTH_BYTES_TRANSFER: {
912                pullBluetoothBytesTransfer(tagId, ret);
913                break;
914            }
915            case StatsLog.KERNEL_WAKELOCK: {
916                pullKernelWakelock(tagId, ret);
917                break;
918            }
919            case StatsLog.CPU_TIME_PER_FREQ: {
920                pullCpuTimePerFreq(tagId, ret);
921                break;
922            }
923            case StatsLog.CPU_TIME_PER_UID: {
924                pullKernelUidCpuTime(tagId, ret);
925                break;
926            }
927            case StatsLog.CPU_TIME_PER_UID_FREQ: {
928                pullKernelUidCpuFreqTime(tagId, ret);
929                break;
930            }
931            case StatsLog.CPU_CLUSTER_TIME: {
932                pullKernelUidCpuClusterTime(tagId, ret);
933                break;
934            }
935            case StatsLog.CPU_ACTIVE_TIME: {
936                pullKernelUidCpuActiveTime(tagId, ret);
937                break;
938            }
939            case StatsLog.WIFI_ACTIVITY_INFO: {
940                pullWifiActivityInfo(tagId, ret);
941                break;
942            }
943            case StatsLog.MODEM_ACTIVITY_INFO: {
944                pullModemActivityInfo(tagId, ret);
945                break;
946            }
947            case StatsLog.BLUETOOTH_ACTIVITY_INFO: {
948                pullBluetoothActivityInfo(tagId, ret);
949                break;
950            }
951            case StatsLog.SYSTEM_UPTIME: {
952                pullSystemUpTime(tagId, ret);
953                break;
954            }
955            case StatsLog.SYSTEM_ELAPSED_REALTIME: {
956                pullSystemElapsedRealtime(tagId, ret);
957                break;
958            }
959            case StatsLog.DISK_SPACE: {
960                pullDiskSpace(tagId, ret);
961                break;
962            }
963            case StatsLog.PROCESS_MEMORY_STATE: {
964                pullProcessMemoryState(tagId, ret);
965                break;
966            }
967            default:
968                Slog.w(TAG, "No such tagId data as " + tagId);
969                return null;
970        }
971        return ret.toArray(new StatsLogEventWrapper[ret.size()]);
972    }
973
974    @Override // Binder call
975    public void statsdReady() {
976        enforceCallingPermission();
977        if (DEBUG) Slog.d(TAG, "learned that statsdReady");
978        sayHiToStatsd(); // tell statsd that we're ready too and link to it
979        mContext.sendBroadcastAsUser(
980                new Intent(StatsManager.ACTION_STATSD_STARTED)
981                        .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
982                UserHandle.SYSTEM,
983                android.Manifest.permission.DUMP);
984    }
985
986    @Override
987    public void triggerUidSnapshot() {
988        enforceCallingPermission();
989        synchronized (sStatsdLock) {
990            final long token = Binder.clearCallingIdentity();
991            try {
992                informAllUidsLocked(mContext);
993            } catch (RemoteException e) {
994                Slog.e(TAG, "Failed to trigger uid snapshot.", e);
995            } finally {
996                restoreCallingIdentity(token);
997            }
998        }
999    }
1000
1001    private void enforceCallingPermission() {
1002        if (Binder.getCallingPid() == Process.myPid()) {
1003            return;
1004        }
1005        mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
1006    }
1007
1008    // Lifecycle and related code
1009
1010    /**
1011     * Fetches the statsd IBinder service
1012     */
1013    private static IStatsManager fetchStatsdService() {
1014        return IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
1015    }
1016
1017    public static final class Lifecycle extends SystemService {
1018        private StatsCompanionService mStatsCompanionService;
1019
1020        public Lifecycle(Context context) {
1021            super(context);
1022        }
1023
1024        @Override
1025        public void onStart() {
1026            mStatsCompanionService = new StatsCompanionService(getContext());
1027            try {
1028                publishBinderService(Context.STATS_COMPANION_SERVICE, mStatsCompanionService);
1029                if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE);
1030            } catch (Exception e) {
1031                Slog.e(TAG, "Failed to publishBinderService", e);
1032            }
1033        }
1034
1035        @Override
1036        public void onBootPhase(int phase) {
1037            super.onBootPhase(phase);
1038            if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
1039                mStatsCompanionService.systemReady();
1040            }
1041        }
1042    }
1043
1044    /**
1045     * Now that the android system is ready, StatsCompanion is ready too, so inform statsd.
1046     */
1047    private void systemReady() {
1048        if (DEBUG) Slog.d(TAG, "Learned that systemReady");
1049        sayHiToStatsd();
1050    }
1051
1052    /**
1053     * Tells statsd that statscompanion is ready. If the binder call returns, link to statsd.
1054     */
1055    private void sayHiToStatsd() {
1056        synchronized (sStatsdLock) {
1057            if (sStatsd != null) {
1058                Slog.e(TAG, "Trying to fetch statsd, but it was already fetched",
1059                        new IllegalStateException("sStatsd is not null when being fetched"));
1060                return;
1061            }
1062            sStatsd = fetchStatsdService();
1063            if (sStatsd == null) {
1064                Slog.i(TAG, "Could not yet find statsd to tell it that StatsCompanion is alive.");
1065                return;
1066            }
1067            if (DEBUG) Slog.d(TAG, "Saying hi to statsd");
1068            try {
1069                sStatsd.statsCompanionReady();
1070                // If the statsCompanionReady two-way binder call returns, link to statsd.
1071                try {
1072                    sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
1073                } catch (RemoteException e) {
1074                    Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
1075                    forgetEverythingLocked();
1076                }
1077                // Setup broadcast receiver for updates.
1078                IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
1079                filter.addAction(Intent.ACTION_PACKAGE_ADDED);
1080                filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1081                filter.addDataScheme("package");
1082                mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null,
1083                        null);
1084
1085                // Setup receiver for user initialize (which happens once for a new user) and
1086                // if a user is removed.
1087                filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
1088                filter.addAction(Intent.ACTION_USER_REMOVED);
1089                mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL,
1090                        filter, null, null);
1091
1092                // Setup receiver for device reboots or shutdowns.
1093                filter = new IntentFilter(Intent.ACTION_REBOOT);
1094                filter.addAction(Intent.ACTION_SHUTDOWN);
1095                mContext.registerReceiverAsUser(
1096                        mShutdownEventReceiver, UserHandle.ALL, filter, null, null);
1097                final long token = Binder.clearCallingIdentity();
1098                try {
1099                    // Pull the latest state of UID->app name, version mapping when statsd starts.
1100                    informAllUidsLocked(mContext);
1101                } finally {
1102                    restoreCallingIdentity(token);
1103                }
1104                Slog.i(TAG, "Told statsd that StatsCompanionService is alive.");
1105            } catch (RemoteException e) {
1106                Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
1107                forgetEverythingLocked();
1108            }
1109        }
1110    }
1111
1112    private class StatsdDeathRecipient implements IBinder.DeathRecipient {
1113        @Override
1114        public void binderDied() {
1115            Slog.i(TAG, "Statsd is dead - erase all my knowledge.");
1116            synchronized (sStatsdLock) {
1117                long now = SystemClock.elapsedRealtime();
1118                for (Long timeMillis : mDeathTimeMillis) {
1119                    long ageMillis = now - timeMillis;
1120                    if (ageMillis > MILLIS_IN_A_DAY) {
1121                        mDeathTimeMillis.remove(timeMillis);
1122                    }
1123                }
1124                for (Long timeMillis : mDeletedFiles.keySet()) {
1125                    long ageMillis = now - timeMillis;
1126                    if (ageMillis > MILLIS_IN_A_DAY * 7) {
1127                        mDeletedFiles.remove(timeMillis);
1128                    }
1129                }
1130                mDeathTimeMillis.add(now);
1131                if (mDeathTimeMillis.size() >= DEATH_THRESHOLD) {
1132                    mDeathTimeMillis.clear();
1133                    File[] configs = FileUtils.listFilesOrEmpty(new File(CONFIG_DIR));
1134                    if (configs.length > 0) {
1135                        String fileName = configs[0].getName();
1136                        if (configs[0].delete()) {
1137                            mDeletedFiles.put(now, fileName);
1138                        }
1139                    }
1140                }
1141                forgetEverythingLocked();
1142            }
1143        }
1144    }
1145
1146    private void forgetEverythingLocked() {
1147        sStatsd = null;
1148        mContext.unregisterReceiver(mAppUpdateReceiver);
1149        mContext.unregisterReceiver(mUserUpdateReceiver);
1150        mContext.unregisterReceiver(mShutdownEventReceiver);
1151        cancelAnomalyAlarm();
1152        cancelPullingAlarm();
1153    }
1154
1155    @Override
1156    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1157        if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
1158
1159        synchronized (sStatsdLock) {
1160            writer.println("Number of configuration files deleted: " + mDeletedFiles.size());
1161            if (mDeletedFiles.size() > 0) {
1162                writer.println("  timestamp, deleted file name");
1163            }
1164            long lastBootMillis =
1165                    SystemClock.currentThreadTimeMillis() - SystemClock.elapsedRealtime();
1166            for (Long elapsedMillis : mDeletedFiles.keySet()) {
1167                long deletionMillis = lastBootMillis + elapsedMillis;
1168                writer.println("  " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
1169            }
1170        }
1171    }
1172
1173}
1174