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