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