Add Bluetooth atoms

+ refactor pullers in StatsCompanionService to be more modular
+ rename CpuSuspendTime and CpuIdleTime to SystemElapsedRealtime
  and SystemUptime

Test: will add cts test
Change-Id: I463103fb271511cef4e0f877c20fd167fe8b173b
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 99e871f..b8ff0bd 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -94,26 +94,27 @@
     }
 
     // Pulled events will start at field 10000.
+    // Next: 10019
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
         MobileBytesTransfer mobile_bytes_transfer = 10002;
         MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg = 10003;
+        BluetoothBytesTransfer bluetooth_bytes_transfer = 10006;
         KernelWakelock kernel_wakelock = 10004;
         SubsystemSleepState subsystem_sleep_state = 10005;
-        // 10006 and 10007 are free to use.
         CpuTimePerFreq cpu_time_per_freq = 10008;
         CpuTimePerUid cpu_time_per_uid = 10009;
         CpuTimePerUidFreq cpu_time_per_uid_freq = 10010;
         WifiActivityEnergyInfo wifi_activity_energy_info = 10011;
         ModemActivityInfo modem_activity_info = 10012;
         ProcessMemoryStat process_memory_stat = 10013;
-        CpuSuspendTime cpu_suspend_time = 10014;
-        CpuIdleTime cpu_idle_time = 10015;
+        BluetoothActivityInfo bluetooth_activity_info = 10007;
+        SystemElapsedRealtime system_elapsed_realtime = 10014;
+        SystemUptime system_uptime = 10015;
         CpuActiveTime cpu_active_time = 10016;
         CpuClusterTime cpu_cluster_time = 10017;
         DiskSpace disk_space = 10018;
-        SystemUptime system_uptime = 10019;
     }
 }
 
@@ -999,6 +1000,20 @@
 }
 
 /**
+ * Pulls bytes transferred via bluetooth. It is pulled from Bluetooth controller.
+ *
+ * Pulled from:
+ *   StatsCompanionService
+ */
+message BluetoothBytesTransfer {
+    optional int32 uid = 1;
+
+    optional int64 rx_bytes = 2;
+
+    optional int64 tx_bytes = 3;
+}
+
+/**
  * Pulls the kernel wakelock durations. This atom is adapted from
  * android/internal/os/KernelWakelockStats.java
  *
@@ -1168,6 +1183,25 @@
     optional uint64 energy_used = 10;
 }
 
+/**
+ * Pulls Bluetooth Activity Energy Info
+ * Note: BluetoothBytesTransfer is pulled at the same time from the controller.
+ */
+message BluetoothActivityInfo {
+    // timestamp(wall clock) of record creation
+    optional uint64 timestamp_ms = 1;
+    // bluetooth stack state
+    optional int32 bluetooth_stack_state = 2;
+    // tx time in ms
+    optional uint64 controller_tx_time_ms = 3;
+    // rx time in ms
+    optional uint64 controller_rx_time_ms = 4;
+    // idle time in ms
+    optional uint64 controller_idle_time_ms = 5;
+    // product of current(mA), voltage(V) and time(ms)
+    optional uint64 energy_used = 6;
+}
+
 /*
  * Logs the memory stats for a process
  */
@@ -1214,17 +1248,21 @@
 }
 
 /*
- * Cpu syspend time for cpu power calculation.
+ * Elapsed real time from SystemClock.
  */
-message CpuSuspendTime {
-    optional uint64 time = 1;
+message SystemElapsedRealtime {
+    optional uint64 time_ms = 1;
 }
 
 /*
- * Cpu idle time for cpu power calculation.
+ * Up time from SystemClock.
  */
-message CpuIdleTime {
-    optional uint64 time = 1;
+message SystemUptime {
+    // Milliseconds since the system was booted.
+    // This clock stops when the system enters deep sleep (CPU off, display dark, device waiting
+    // for external input).
+    // It is not affected by clock scaling, idle, or other power saving mechanisms.
+    optional uint64 uptime_ms = 1;
 }
 
 /*
@@ -1268,14 +1306,3 @@
     // available bytes in download cache or temp directories
     optional uint64 temp_available_bytes = 3;
 }
-
-/*
- * Pulls system up time.
- */
-message SystemUptime {
-    // Milliseconds since the system was booted.
-    // This clock stops when the system enters deep sleep (CPU off, display dark, device waiting
-    // for external input).
-    // It is not affected by clock scaling, idle, or other power saving mechanisms.
-    optional uint64 uptime_ms = 1;
-}
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index e06ae48..148c9ae 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -64,12 +64,20 @@
     mPullers.insert({android::util::CPU_TIME_PER_FREQ, make_shared<StatsCompanionServicePuller>(android::util::CPU_TIME_PER_FREQ)});
     mPullers.insert({android::util::CPU_TIME_PER_UID, make_shared<CpuTimePerUidPuller>()});
     mPullers.insert({android::util::CPU_TIME_PER_UID_FREQ, make_shared<CpuTimePerUidFreqPuller>()});
-    mPullers.insert({android::util::CPU_SUSPEND_TIME, make_shared<StatsCompanionServicePuller>(android::util::CPU_SUSPEND_TIME)});
-    mPullers.insert({android::util::CPU_IDLE_TIME, make_shared<StatsCompanionServicePuller>(android::util::CPU_IDLE_TIME)});
-    mPullers.insert({android::util::DISK_SPACE,
-                     make_shared<StatsCompanionServicePuller>(android::util::DISK_SPACE)});
+    mPullers.insert(
+            {android::util::SYSTEM_ELAPSED_REALTIME,
+             make_shared<StatsCompanionServicePuller>(android::util::SYSTEM_ELAPSED_REALTIME)});
     mPullers.insert({android::util::SYSTEM_UPTIME,
                      make_shared<StatsCompanionServicePuller>(android::util::SYSTEM_UPTIME)});
+    mPullers.insert({android::util::DISK_SPACE,
+                     make_shared<StatsCompanionServicePuller>(android::util::DISK_SPACE)});
+    mPullers.insert(
+            {android::util::BLUETOOTH_ACTIVITY_INFO,
+             make_shared<StatsCompanionServicePuller>(android::util::BLUETOOTH_ACTIVITY_INFO)});
+
+    mPullers.insert(
+            {android::util::BLUETOOTH_BYTES_TRANSFER,
+             make_shared<StatsCompanionServicePuller>(android::util::BLUETOOTH_BYTES_TRANSFER)});
     mPullers.insert(
             {android::util::WIFI_ACTIVITY_ENERGY_INFO,
              make_shared<StatsCompanionServicePuller>(android::util::WIFI_ACTIVITY_ENERGY_INFO)});
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index cfdec4c..dc648b3 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -19,6 +19,9 @@
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.app.StatsManager;
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.UidTraffic;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -30,7 +33,6 @@
 import android.net.NetworkStats;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.WifiActivityEnergyInfo;
-import android.os.StatsDimensionsValue;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
 import android.os.Bundle;
@@ -43,6 +45,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
+import android.os.StatsDimensionsValue;
 import android.os.StatsLogEventWrapper;
 import android.os.SynchronousResultReceiver;
 import android.os.SystemClock;
@@ -110,6 +113,7 @@
         new StatFs(Environment.getRootDirectory().getAbsolutePath());
     private final StatFs mStatFsTemp =
         new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
+    private final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
 
     public StatsCompanionService(Context context) {
         super();
@@ -402,24 +406,23 @@
       }
     }
 
-    private StatsLogEventWrapper[] addNetworkStats(int tag, NetworkStats stats, boolean withFGBG) {
-        List<StatsLogEventWrapper> ret = new ArrayList<>();
-        int size = stats.size();
-        NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
-        for (int j = 0; j < size; j++) {
-            stats.getValues(j, entry);
-            StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5);
-            e.writeInt(entry.uid);
-            if (withFGBG) {
-                e.writeInt(entry.set);
-            }
-            e.writeLong(entry.rxBytes);
-            e.writeLong(entry.rxPackets);
-            e.writeLong(entry.txBytes);
-            e.writeLong(entry.txPackets);
-            ret.add(e);
+    private void addNetworkStats(
+        int tag, List<StatsLogEventWrapper> ret, NetworkStats stats, boolean withFGBG) {
+      int size = stats.size();
+      NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
+      for (int j = 0; j < size; j++) {
+        stats.getValues(j, entry);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5);
+        e.writeInt(entry.uid);
+        if (withFGBG) {
+          e.writeInt(entry.set);
         }
-        return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+        e.writeLong(entry.rxBytes);
+        e.writeLong(entry.rxPackets);
+        e.writeLong(entry.txBytes);
+        e.writeLong(entry.txPackets);
+        ret.add(e);
+      }
     }
 
     /**
@@ -485,220 +488,289 @@
         return null;
     }
 
+    private void pullKernelWakelock(int tagId, List<StatsLogEventWrapper> pulledData) {
+      final KernelWakelockStats wakelockStats =
+          mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
+      for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
+        String name = ent.getKey();
+        KernelWakelockStats.Entry kws = ent.getValue();
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4);
+        e.writeString(name);
+        e.writeInt(kws.mCount);
+        e.writeInt(kws.mVersion);
+        e.writeLong(kws.mTotalTime);
+        pulledData.add(e);
+      }
+    }
+
+    private void pullWifiBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
+      long token = Binder.clearCallingIdentity();
+      try {
+        // TODO: Consider caching the following call to get BatteryStatsInternal.
+        BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+        String[] ifaces = bs.getWifiIfaces();
+        if (ifaces.length == 0) {
+          return;
+        }
+        NetworkStatsFactory nsf = new NetworkStatsFactory();
+        // Combine all the metrics per Uid into one record.
+        NetworkStats stats =
+            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
+                .groupedByUid();
+        addNetworkStats(tagId, pulledData, stats, false);
+      } catch (java.io.IOException e) {
+        Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
+      } finally {
+        Binder.restoreCallingIdentity(token);
+      }
+    }
+
+    private void pullWifiBytesTransferByFgBg(int tagId, List<StatsLogEventWrapper> pulledData) {
+      long token = Binder.clearCallingIdentity();
+      try {
+        BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+        String[] ifaces = bs.getWifiIfaces();
+        if (ifaces.length == 0) {
+          return;
+        }
+        NetworkStatsFactory nsf = new NetworkStatsFactory();
+        NetworkStats stats = rollupNetworkStatsByFGBG(
+            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
+        addNetworkStats(tagId, pulledData, stats, true);
+      } catch (java.io.IOException e) {
+        Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
+      } finally {
+        Binder.restoreCallingIdentity(token);
+      }
+    }
+
+    private void pullMobileBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
+      long token = Binder.clearCallingIdentity();
+      try {
+        BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+        String[] ifaces = bs.getMobileIfaces();
+        if (ifaces.length == 0) {
+          return;
+        }
+        NetworkStatsFactory nsf = new NetworkStatsFactory();
+        // Combine all the metrics per Uid into one record.
+        NetworkStats stats =
+            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
+                .groupedByUid();
+        addNetworkStats(tagId, pulledData, stats, false);
+      } catch (java.io.IOException e) {
+        Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
+      } finally {
+        Binder.restoreCallingIdentity(token);
+      }
+    }
+
+    private void pullBluetoothBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
+      BluetoothActivityEnergyInfo info = pullBluetoothData();
+      for (UidTraffic traffic : info.getUidTraffic()) {
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
+        e.writeInt(traffic.getUid());
+        e.writeLong(traffic.getRxBytes());
+        e.writeLong(traffic.getTxBytes());
+        pulledData.add(e);
+      }
+    }
+
+    private void pullMobileBytesTransferByFgBg(int tagId, List<StatsLogEventWrapper> pulledData) {
+      long token = Binder.clearCallingIdentity();
+      try {
+        BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+        String[] ifaces = bs.getMobileIfaces();
+        if (ifaces.length == 0) {
+          return;
+        }
+        NetworkStatsFactory nsf = new NetworkStatsFactory();
+        NetworkStats stats = rollupNetworkStatsByFGBG(
+            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
+        addNetworkStats(tagId, pulledData, stats, true);
+      } catch (java.io.IOException e) {
+        Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
+      } finally {
+        Binder.restoreCallingIdentity(token);
+      }
+    }
+
+    private void pullCpuTimePerFreq(int tagId, List<StatsLogEventWrapper> pulledData) {
+      for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
+        long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
+        if (clusterTimeMs != null) {
+          for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
+            e.writeInt(cluster);
+            e.writeInt(speed);
+            e.writeLong(clusterTimeMs[speed]);
+            pulledData.add(e);
+          }
+        }
+      }
+    }
+
+    private void pullWifiActivityEnergyInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
+      long token = Binder.clearCallingIdentity();
+      if (mWifiManager == null) {
+        mWifiManager =
+            IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE));
+      }
+      if (mWifiManager != null) {
+        try {
+          SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
+          mWifiManager.requestActivityInfo(wifiReceiver);
+          final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
+          StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+          e.writeLong(wifiInfo.getTimeStamp());
+          e.writeInt(wifiInfo.getStackState());
+          e.writeLong(wifiInfo.getControllerTxTimeMillis());
+          e.writeLong(wifiInfo.getControllerRxTimeMillis());
+          e.writeLong(wifiInfo.getControllerIdleTimeMillis());
+          e.writeLong(wifiInfo.getControllerEnergyUsed());
+          pulledData.add(e);
+        } catch (RemoteException e) {
+          Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e);
+        } finally {
+          Binder.restoreCallingIdentity(token);
+        }
+      }
+    }
+
+    private void pullModemActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
+      long token = Binder.clearCallingIdentity();
+      if (mTelephony == null) {
+        mTelephony = TelephonyManager.from(mContext);
+      }
+      if (mTelephony != null) {
+        SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
+        mTelephony.requestModemActivityInfo(modemReceiver);
+        final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+        e.writeLong(modemInfo.getTimestamp());
+        e.writeLong(modemInfo.getSleepTimeMillis());
+        e.writeLong(modemInfo.getIdleTimeMillis());
+        e.writeLong(modemInfo.getTxTimeMillis()[0]);
+        e.writeLong(modemInfo.getTxTimeMillis()[1]);
+        e.writeLong(modemInfo.getTxTimeMillis()[2]);
+        e.writeLong(modemInfo.getTxTimeMillis()[3]);
+        e.writeLong(modemInfo.getTxTimeMillis()[4]);
+        e.writeLong(modemInfo.getRxTimeMillis());
+        e.writeLong(modemInfo.getEnergyUsed());
+        pulledData.add(e);
+      }
+    }
+
+    private void pullBluetoothActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
+      BluetoothActivityEnergyInfo info = pullBluetoothData();
+      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+      e.writeLong(info.getTimeStamp());
+      e.writeInt(info.getBluetoothStackState());
+      e.writeLong(info.getControllerTxTimeMillis());
+      e.writeLong(info.getControllerRxTimeMillis());
+      e.writeLong(info.getControllerIdleTimeMillis());
+      e.writeLong(info.getControllerEnergyUsed());
+      pulledData.add(e);
+    }
+
+    private synchronized BluetoothActivityEnergyInfo pullBluetoothData() {
+      if (adapter != null) {
+        SynchronousResultReceiver bluetoothReceiver = null;
+        bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
+        adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+        return awaitControllerInfo(bluetoothReceiver);
+      } else {
+        return null;
+      }
+    }
+
+    private void pullSystemElapsedRealtime(int tagId, List<StatsLogEventWrapper> pulledData) {
+      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
+      e.writeLong(SystemClock.elapsedRealtime());
+      pulledData.add(e);
+    }
+
+    private void pullDiskSpace(int tagId, List<StatsLogEventWrapper> pulledData) {
+      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
+      e.writeLong(mStatFsData.getAvailableBytes());
+      e.writeLong(mStatFsSystem.getAvailableBytes());
+      e.writeLong(mStatFsTemp.getAvailableBytes());
+      pulledData.add(e);
+    }
+
+    private void pullSystemUpTime(int tagId, List<StatsLogEventWrapper> pulledData) {
+      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
+      e.writeLong(SystemClock.uptimeMillis());
+      pulledData.add(e);
+    }
+
     /**
-     *
-     * Pulls wifi controller activity energy info from WiFiManager
+     * Pulls various data.
      */
     @Override // Binder call
     public StatsLogEventWrapper[] pullData(int tagId) {
         enforceCallingPermission();
         if (DEBUG)
             Slog.d(TAG, "Pulling " + tagId);
-
+        List<StatsLogEventWrapper> ret = new ArrayList();
         switch (tagId) {
             case StatsLog.WIFI_BYTES_TRANSFER: {
-                long token = Binder.clearCallingIdentity();
-                try {
-                    // TODO: Consider caching the following call to get BatteryStatsInternal.
-                    BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-                    String[] ifaces = bs.getWifiIfaces();
-                    if (ifaces.length == 0) {
-                        return null;
-                    }
-                    NetworkStatsFactory nsf = new NetworkStatsFactory();
-                    // Combine all the metrics per Uid into one record.
-                    NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
-                            NetworkStats.TAG_NONE, null).groupedByUid();
-                    return addNetworkStats(tagId, stats, false);
-                } catch (java.io.IOException e) {
-                    Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-                break;
+              pullWifiBytesTransfer(tagId, ret);
+              break;
             }
             case StatsLog.MOBILE_BYTES_TRANSFER: {
-                long token = Binder.clearCallingIdentity();
-                try {
-                    BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-                    String[] ifaces = bs.getMobileIfaces();
-                    if (ifaces.length == 0) {
-                        return null;
-                    }
-                    NetworkStatsFactory nsf = new NetworkStatsFactory();
-                    // Combine all the metrics per Uid into one record.
-                    NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
-                        NetworkStats.TAG_NONE, null).groupedByUid();
-                    return addNetworkStats(tagId, stats, false);
-                } catch (java.io.IOException e) {
-                    Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-                break;
+              pullMobileBytesTransfer(tagId, ret);
+              break;
             }
             case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
-                long token = Binder.clearCallingIdentity();
-                try {
-                    BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-                    String[] ifaces = bs.getWifiIfaces();
-                    if (ifaces.length == 0) {
-                        return null;
-                    }
-                    NetworkStatsFactory nsf = new NetworkStatsFactory();
-                    NetworkStats stats = rollupNetworkStatsByFGBG(
-                            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
-                            NetworkStats.TAG_NONE, null));
-                    return addNetworkStats(tagId, stats, true);
-                } catch (java.io.IOException e) {
-                    Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-                break;
+              pullWifiBytesTransferByFgBg(tagId, ret);
+              break;
             }
             case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
-                long token = Binder.clearCallingIdentity();
-                try {
-                    BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-                    String[] ifaces = bs.getMobileIfaces();
-                    if (ifaces.length == 0) {
-                        return null;
-                    }
-                    NetworkStatsFactory nsf = new NetworkStatsFactory();
-                    NetworkStats stats = rollupNetworkStatsByFGBG(
-                            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
-                            NetworkStats.TAG_NONE, null));
-                    return addNetworkStats(tagId, stats, true);
-                } catch (java.io.IOException e) {
-                    Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-                break;
+              pullMobileBytesTransferByFgBg(tagId, ret);
+              break;
+            }
+            case StatsLog.BLUETOOTH_BYTES_TRANSFER: {
+              pullBluetoothBytesTransfer(tagId, ret);
+              break;
             }
             case StatsLog.KERNEL_WAKELOCK: {
-                final KernelWakelockStats wakelockStats =
-                        mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
-                List<StatsLogEventWrapper> ret = new ArrayList();
-                for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
-                    String name = ent.getKey();
-                    KernelWakelockStats.Entry kws = ent.getValue();
-                    StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4);
-                    e.writeString(name);
-                    e.writeInt(kws.mCount);
-                    e.writeInt(kws.mVersion);
-                    e.writeLong(kws.mTotalTime);
-                    ret.add(e);
-                }
-                return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+              pullKernelWakelock(tagId, ret);
+              break;
             }
             case StatsLog.CPU_TIME_PER_FREQ: {
-                List<StatsLogEventWrapper> ret = new ArrayList();
-                for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
-                    long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
-                    if (clusterTimeMs != null) {
-                        for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
-                            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
-                            e.writeInt(cluster);
-                            e.writeInt(speed);
-                            e.writeLong(clusterTimeMs[speed]);
-                            ret.add(e);
-                        }
-                    }
-                }
-                return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+              pullCpuTimePerFreq(tagId, ret);
+              break;
             }
             case StatsLog.WIFI_ACTIVITY_ENERGY_INFO: {
-                List<StatsLogEventWrapper> ret = new ArrayList();
-                long token = Binder.clearCallingIdentity();
-                if (mWifiManager == null) {
-                    mWifiManager = IWifiManager.Stub.asInterface(ServiceManager.getService(
-                            Context.WIFI_SERVICE));
-                }
-                if (mWifiManager != null) {
-                    try {
-                        SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
-                        mWifiManager.requestActivityInfo(wifiReceiver);
-                        final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
-                        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
-                        e.writeLong(wifiInfo.getTimeStamp());
-                        e.writeInt(wifiInfo.getStackState());
-                        e.writeLong(wifiInfo.getControllerTxTimeMillis());
-                        e.writeLong(wifiInfo.getControllerRxTimeMillis());
-                        e.writeLong(wifiInfo.getControllerIdleTimeMillis());
-                        e.writeLong(wifiInfo.getControllerEnergyUsed());
-                        ret.add(e);
-                        return ret.toArray(new StatsLogEventWrapper[ret.size()]);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e);
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                    }
-                }
-                break;
+              pullWifiActivityEnergyInfo(tagId, ret);
+              break;
             }
             case StatsLog.MODEM_ACTIVITY_INFO: {
-                List<StatsLogEventWrapper> ret = new ArrayList();
-                long token = Binder.clearCallingIdentity();
-                if (mTelephony == null) {
-                    mTelephony = TelephonyManager.from(mContext);
-                }
-                if (mTelephony != null) {
-                    SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
-                    mTelephony.requestModemActivityInfo(modemReceiver);
-                    final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
-                    StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 10);
-                    e.writeLong(modemInfo.getTimestamp());
-                    e.writeLong(modemInfo.getSleepTimeMillis());
-                    e.writeLong(modemInfo.getIdleTimeMillis());
-                    e.writeLong(modemInfo.getTxTimeMillis()[0]);
-                    e.writeLong(modemInfo.getTxTimeMillis()[1]);
-                    e.writeLong(modemInfo.getTxTimeMillis()[2]);
-                    e.writeLong(modemInfo.getTxTimeMillis()[3]);
-                    e.writeLong(modemInfo.getTxTimeMillis()[4]);
-                    e.writeLong(modemInfo.getRxTimeMillis());
-                    e.writeLong(modemInfo.getEnergyUsed());
-                    ret.add(e);
-                    return ret.toArray(new StatsLogEventWrapper[ret.size()]);
-                }
-                break;
+              pullModemActivityInfo(tagId, ret);
+              break;
             }
-            case StatsLog.CPU_SUSPEND_TIME: {
-                List<StatsLogEventWrapper> ret = new ArrayList();
-                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
-                e.writeLong(SystemClock.elapsedRealtime());
-                ret.add(e);
-                return ret.toArray(new StatsLogEventWrapper[ret.size()]);
-            }
-            case StatsLog.CPU_IDLE_TIME: {
-                List<StatsLogEventWrapper> ret = new ArrayList();
-                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
-                e.writeLong(SystemClock.uptimeMillis());
-                ret.add(e);
-                return ret.toArray(new StatsLogEventWrapper[ret.size()]);
-            }
-            case StatsLog.DISK_SPACE: {
-              List<StatsLogEventWrapper> ret = new ArrayList();
-              StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
-              e.writeLong(mStatFsData.getAvailableBytes());
-              e.writeLong(mStatFsSystem.getAvailableBytes());
-              e.writeLong(mStatFsTemp.getAvailableBytes());
-              ret.add(e);
-              return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+            case StatsLog.BLUETOOTH_ACTIVITY_INFO: {
+              pullBluetoothActivityInfo(tagId, ret);
+              break;
             }
             case StatsLog.SYSTEM_UPTIME: {
-              List<StatsLogEventWrapper> ret = new ArrayList();
-              StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
-              e.writeLong(SystemClock.uptimeMillis());
-              ret.add(e);
-              return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+              pullSystemUpTime(tagId, ret);
+              break;
+            }
+            case StatsLog.SYSTEM_ELAPSED_REALTIME: {
+              pullSystemElapsedRealtime(tagId, ret);
+              break;
+            }
+            case StatsLog.DISK_SPACE: {
+              pullDiskSpace(tagId, ret);
+              break;
             }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
                 return null;
         }
-        return null;
+        return ret.toArray(new StatsLogEventWrapper[ret.size()]);
     }
 
     @Override // Binder call