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