Merge "Statsd notifies listener with pendingintent."
diff --git a/api/system-current.txt b/api/system-current.txt
index f7e7d60..32d235d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30,8 +30,8 @@
     field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
     field public static final java.lang.String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
     field public static final java.lang.String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
-    field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
     field public static final java.lang.String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
+    field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
     field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
     field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
@@ -361,11 +361,12 @@
   }
 
   public final class StatsManager {
-    method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String);
+    method public boolean addConfiguration(long, byte[]);
     method public byte[] getData(long);
     method public byte[] getMetadata();
     method public boolean removeConfiguration(long);
     method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
+    method public boolean setDataFetchOperation(long, android.app.PendingIntent);
     field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
     field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
     field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index f24bb04..183a995 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -84,12 +84,11 @@
         auto receiver = mConfigManager->GetConfigReceiver(key);
         if (sc == nullptr) {
             VLOG("Could not find StatsCompanionService");
-        } else if (receiver.first.size() == 0) {
+        } else if (receiver == nullptr) {
             VLOG("Statscompanion could not find a broadcast receiver for %s",
                  key.ToString().c_str());
         } else {
-            sc->sendBroadcast(String16(receiver.first.c_str()),
-                              String16(receiver.second.c_str()));
+            sc->sendDataBroadcast(receiver);
         }
     });
 
@@ -367,12 +366,14 @@
     }
     auto receiver = mConfigManager->GetConfigReceiver(ConfigKey(uid, StrToInt64(name)));
     sp<IStatsCompanionService> sc = getStatsCompanionService();
-    if (sc != nullptr) {
-        sc->sendBroadcast(String16(receiver.first.c_str()), String16(receiver.second.c_str()));
+    if (sc == nullptr) {
+        VLOG("Could not access statsCompanion");
+    } else if (receiver == nullptr) {
+        VLOG("Could not find receiver for %s, %s", args[1].c_str(), args[2].c_str())
+    } else {
+        sc->sendDataBroadcast(receiver);
         VLOG("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(),
              args[2].c_str());
-    } else {
-        VLOG("Could not access statsCompanion");
     }
 
     return NO_ERROR;
@@ -800,7 +801,6 @@
 
 Status StatsService::addConfiguration(int64_t key,
                                       const vector <uint8_t>& config,
-                                      const String16& package, const String16& cls,
                                       bool* success) {
     IPCThreadState* ipc = IPCThreadState::self();
     if (checkCallingPermission(String16(kPermissionDump))) {
@@ -811,8 +811,33 @@
             return Status::ok();
         }
         mConfigManager->UpdateConfig(configKey, cfg);
-        mConfigManager->SetConfigReceiver(configKey, string(String8(package).string()),
-                                          string(String8(cls).string()));
+        *success = true;
+        return Status::ok();
+    } else {
+        *success = false;
+        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
+    }
+}
+
+Status StatsService::removeDataFetchOperation(int64_t key, bool* success) {
+    IPCThreadState* ipc = IPCThreadState::self();
+    if (checkCallingPermission(String16(kPermissionDump))) {
+        ConfigKey configKey(ipc->getCallingUid(), key);
+        mConfigManager->RemoveConfigReceiver(configKey);
+        *success = true;
+        return Status::ok();
+    } else {
+        *success = false;
+        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
+    }
+}
+
+Status StatsService::setDataFetchOperation(int64_t key, const sp<android::IBinder>& intentSender,
+                                           bool* success) {
+    IPCThreadState* ipc = IPCThreadState::self();
+    if (checkCallingPermission(String16(kPermissionDump))) {
+        ConfigKey configKey(ipc->getCallingUid(), key);
+        mConfigManager->SetConfigReceiver(configKey, intentSender);
         *success = true;
         return Status::ok();
     } else {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 109752b..3dc19fe 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -90,9 +90,19 @@
      * Binder call to let clients send a configuration and indicate they're interested when they
      * should requestData for this configuration.
      */
-    virtual Status addConfiguration(int64_t key, const vector <uint8_t>& config,
-                                    const String16& package, const String16& cls, bool* success)
-    override;
+    virtual Status addConfiguration(int64_t key, const vector<uint8_t>& config,
+                                    bool* success) override;
+
+    /**
+     * Binder call to let clients register the data fetch operation for a configuration.
+     */
+    virtual Status setDataFetchOperation(int64_t key, const sp<android::IBinder>& intentSender,
+                                         bool* success) override;
+
+    /**
+     * Binder call to remove the data fetch operation for the specified config key.
+     */
+    virtual Status removeDataFetchOperation(int64_t key, bool* success) override;
 
     /**
      * Binder call to allow clients to remove the specified configuration.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 61eeee3..06ff603 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -75,8 +75,8 @@
     }
 }
 
-void ConfigManager::SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls) {
-    mConfigReceivers[key] = pair<string, string>(pkg, cls);
+void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) {
+    mConfigReceivers[key] = intentSender;
 }
 
 void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
@@ -159,10 +159,10 @@
     return ret;
 }
 
-const pair<string, string> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
+const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
     auto it = mConfigReceivers.find(key);
     if (it == mConfigReceivers.end()) {
-        return pair<string,string>();
+        return nullptr;
     } else {
         return it->second;
     }
@@ -175,8 +175,7 @@
         fprintf(out, "  %6d %lld\n", key.GetUid(), (long long)key.GetId());
         auto receiverIt = mConfigReceivers.find(key);
         if (receiverIt != mConfigReceivers.end()) {
-            fprintf(out, "    -> received by %s, %s\n", receiverIt->second.first.c_str(),
-                    receiverIt->second.second.c_str());
+            fprintf(out, "    -> received by PendingIntent as binder\n");
         }
     }
 }
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index ad666bc..a2b2a0c 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "binder/IBinder.h"
 #include "config/ConfigKey.h"
 #include "config/ConfigListener.h"
 
@@ -68,12 +69,12 @@
     /**
      * Sets the broadcast receiver for a configuration key.
      */
-    void SetConfigReceiver(const ConfigKey& key, const std::string& pkg, const std::string& cls);
+    void SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender);
 
     /**
      * Returns the package name and class name representing the broadcast receiver for this config.
      */
-    const std::pair<std::string, std::string> GetConfigReceiver(const ConfigKey& key) const;
+    const sp<android::IBinder> GetConfigReceiver(const ConfigKey& key) const;
 
     /**
      * Returns all config keys registered.
@@ -124,10 +125,10 @@
     std::set<ConfigKey> mConfigs;
 
     /**
-     * Each config key can be subscribed by up to one receiver, specified as the package name and
-     * class name.
+     * Each config key can be subscribed by up to one receiver, specified as IBinder from
+     * PendingIntent.
      */
-    std::map<ConfigKey, std::pair<std::string, std::string>> mConfigReceivers;
+    std::map<ConfigKey, sp<android::IBinder>> mConfigReceivers;
 
     /**
      * The ConfigListeners that will be told about changes.
diff --git a/cmds/statsd/tools/dogfood/AndroidManifest.xml b/cmds/statsd/tools/dogfood/AndroidManifest.xml
index cd76c9d..52673fb 100644
--- a/cmds/statsd/tools/dogfood/AndroidManifest.xml
+++ b/cmds/statsd/tools/dogfood/AndroidManifest.xml
@@ -37,5 +37,7 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <service android:name=".MainActivity$ReceiverIntentService" android:exported="true" />
     </application>
 </manifest>
diff --git a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml b/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
index 5d35c29..784ed40 100644
--- a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
+++ b/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
@@ -31,6 +31,18 @@
             android:layout_height="wrap_content"
             android:background="@android:color/holo_green_light"
             android:text="@string/push_config"/>
+        <Button
+                android:id="@+id/set_receiver"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@android:color/holo_green_light"
+                android:text="@string/set_receiver"/>
+        <Button
+                android:id="@+id/remove_receiver"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@android:color/holo_green_light"
+                android:text="@string/remove_receiver"/>
 
         <LinearLayout android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/cmds/statsd/tools/dogfood/res/values/strings.xml b/cmds/statsd/tools/dogfood/res/values/strings.xml
index 0eab0f4..60948a1 100644
--- a/cmds/statsd/tools/dogfood/res/values/strings.xml
+++ b/cmds/statsd/tools/dogfood/res/values/strings.xml
@@ -24,6 +24,8 @@
     <string name="statsd_not_running">Statsd NOT Running</string>
 
     <string name="push_config">Push baseline config</string>
+    <string name="set_receiver">Set pendingintent</string>
+    <string name="remove_receiver">Remove pendingintent</string>
 
     <string name="app_a_foreground">App A foreground</string>
     <string name="app_b_foreground">App B foreground</string>
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
index 57575ae..0e6c933 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
@@ -16,7 +16,10 @@
 package com.android.statsd.dogfood;
 
 import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.IntentService;
 import android.app.StatsManager;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Bundle;
@@ -48,69 +51,69 @@
 
         findViewById(R.id.app_a_wake_lock_acquire1).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockAcquire(0, "wl_1");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockAcquire(0, "wl_1");
+                    }
+                });
 
         findViewById(R.id.app_b_wake_lock_acquire1).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockAcquire(1, "wl_1");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockAcquire(1, "wl_1");
+                    }
+                });
 
         findViewById(R.id.app_a_wake_lock_acquire2).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockAcquire(0, "wl_2");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockAcquire(0, "wl_2");
+                    }
+                });
 
         findViewById(R.id.app_b_wake_lock_acquire2).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockAcquire(1, "wl_2");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockAcquire(1, "wl_2");
+                    }
+                });
 
         findViewById(R.id.app_a_wake_lock_release1).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockRelease(0, "wl_1");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockRelease(0, "wl_1");
+                    }
+                });
 
 
         findViewById(R.id.app_b_wake_lock_release1).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockRelease(1, "wl_1");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockRelease(1, "wl_1");
+                    }
+                });
 
         findViewById(R.id.app_a_wake_lock_release2).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockRelease(0, "wl_2");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockRelease(0, "wl_2");
+                    }
+                });
 
 
         findViewById(R.id.app_b_wake_lock_release2).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockRelease(1, "wl_2");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockRelease(1, "wl_2");
+                    }
+                });
 
 
         findViewById(R.id.plug).setOnClickListener(new View.OnClickListener() {
@@ -191,8 +194,7 @@
                     byte[] config = new byte[inputStream.available()];
                     inputStream.read(config);
                     if (mStatsManager != null) {
-                        if (mStatsManager.addConfiguration(CONFIG_ID,
-                                config, getPackageName(), MainActivity.this.getClass().getName())) {
+                        if (mStatsManager.addConfiguration(CONFIG_ID, config)) {
                             Toast.makeText(
                                     MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
                         } else {
@@ -205,6 +207,55 @@
                 }
             }
         });
+
+        PendingIntent pi = PendingIntent.getService(this, 0,
+                new Intent(this, ReceiverIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
+        findViewById(R.id.set_receiver).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                try {
+                    if (!statsdRunning()) {
+                        return;
+                    }
+                    if (mStatsManager != null) {
+                        if (mStatsManager.setDataFetchOperation(CONFIG_ID, pi)) {
+                            Toast.makeText(MainActivity.this,
+                                    "Receiver specified to pending intent", Toast.LENGTH_LONG)
+                                    .show();
+                        } else {
+                            Toast.makeText(MainActivity.this, "Statsd did not set receiver",
+                                    Toast.LENGTH_LONG)
+                                    .show();
+                        }
+                    }
+                } catch (Exception e) {
+                    Toast.makeText(MainActivity.this, "failed to set receiver", Toast.LENGTH_LONG);
+                }
+            }
+        });
+        findViewById(R.id.remove_receiver).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                try {
+                    if (!statsdRunning()) {
+                        return;
+                    }
+                    if (mStatsManager != null) {
+                        if (mStatsManager.setDataFetchOperation(CONFIG_ID, null)) {
+                            Toast.makeText(MainActivity.this, "Receiver remove", Toast.LENGTH_LONG)
+                                    .show();
+                        } else {
+                            Toast.makeText(MainActivity.this, "Statsd did not remove receiver",
+                                    Toast.LENGTH_LONG)
+                                    .show();
+                        }
+                    }
+                } catch (Exception e) {
+                    Toast.makeText(
+                            MainActivity.this, "failed to remove receiver", Toast.LENGTH_LONG);
+                }
+            }
+        });
         mStatsManager = (StatsManager) getSystemService("stats");
     }
 
@@ -257,8 +308,8 @@
             Log.d(TAG, "invalid pkg id");
             return;
         }
-        int[] uids = new int[] {mUids[id]};
-        String[] tags  = new String[] {"acquire"};
+        int[] uids = new int[]{mUids[id]};
+        String[] tags = new String[]{"acquire"};
         StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
                 StatsLog.WAKELOCK_STATE_CHANGED__LEVEL__PARTIAL_WAKE_LOCK, name,
                 StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
@@ -273,8 +324,8 @@
             Log.d(TAG, "invalid pkg id");
             return;
         }
-        int[] uids = new int[] {mUids[id]};
-        String[] tags  = new String[] {"release"};
+        int[] uids = new int[]{mUids[id]};
+        String[] tags = new String[]{"release"};
         StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
                 StatsLog.WAKELOCK_STATE_CHANGED__LEVEL__PARTIAL_WAKE_LOCK, name,
                 StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
@@ -283,4 +334,20 @@
                 .append(", ").append(name).append(", 0);");
         Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
     }
+
+    public static class ReceiverIntentService extends IntentService {
+        public ReceiverIntentService() {
+            super("ReceiverIntentService");
+        }
+
+        /**
+         * The IntentService calls this method from the default worker thread with
+         * the intent that started the service. When this method returns, IntentService
+         * stops the service, as appropriate.
+         */
+        @Override
+        protected void onHandleIntent(Intent intent) {
+            Log.i(TAG, "Received notification that we should call getData");
+        }
+    }
 }
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
index 652f6b2..bed4d98 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
@@ -47,10 +47,12 @@
 import android.widget.Spinner;
 import android.widget.TextView;
 import android.widget.Toast;
+
 import com.android.os.StatsLog.ConfigMetricsReport;
 import com.android.os.StatsLog.ConfigMetricsReportList;
 import com.android.os.StatsLog.StatsdStatsReport;
 import com.android.internal.os.StatsdConfigProto.TimeUnit;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -60,18 +62,18 @@
  * Runs a load test for statsd.
  * How it works:
  * <ul>
- *   <li> Sets up and pushes a custom config with metrics that exercise a large swath of code paths.
- *   <li> Periodically logs certain atoms into logd.
- *   <li> Impact on battery can be printed to logcat, or a bug report can be filed and analyzed
- *        in battery Historian.
+ * <li> Sets up and pushes a custom config with metrics that exercise a large swath of code paths.
+ * <li> Periodically logs certain atoms into logd.
+ * <li> Impact on battery can be printed to logcat, or a bug report can be filed and analyzed
+ * in battery Historian.
  * </ul>
  * The load depends on how demanding the config is, as well as how frequently atoms are pushsed
  * to logd. Those are all controlled by 4 adjustable parameters:
  * <ul>
- *   <li> The 'replication' parameter artificially multiplies the number of metrics in the config.
- *   <li> The bucket size controls the time-bucketing the aggregate metrics.
- *   <li> The period parameter controls how frequently atoms are pushed to logd.
- *   <li> The 'burst' parameter controls how many atoms are pushed at the same time (per period).
+ * <li> The 'replication' parameter artificially multiplies the number of metrics in the config.
+ * <li> The bucket size controls the time-bucketing the aggregate metrics.
+ * <li> The period parameter controls how frequently atoms are pushed to logd.
+ * <li> The 'burst' parameter controls how many atoms are pushed at the same time (per period).
  * </ul>
  */
 public class LoadtestActivity extends Activity implements AdapterView.OnItemSelectedListener {
@@ -93,7 +95,7 @@
             Intent activityIntent = new Intent(context, LoadtestActivity.class);
             activityIntent.putExtra(TYPE, PUSH_ALARM);
             context.startActivity(activityIntent);
-         }
+        }
     }
 
     public final static class StopperAlarmReceiver extends BroadcastReceiver {
@@ -102,7 +104,7 @@
             Intent activityIntent = new Intent(context, LoadtestActivity.class);
             activityIntent.putExtra(TYPE, STOP);
             context.startActivity(activityIntent);
-         }
+        }
     }
 
     private static Map<String, TimeUnit> initializeTimeUnitMap() {
@@ -119,6 +121,7 @@
         labels.put("1s", TimeUnit.CTS);
         return labels;
     }
+
     private static List<String> initializeTimeUnitLabels() {
         List<String> labels = new ArrayList();
         labels.add("1s");
@@ -136,10 +139,14 @@
 
     private AlarmManager mAlarmMgr;
 
-    /** Used to periodically log atoms to logd. */
+    /**
+     * Used to periodically log atoms to logd.
+     */
     private PendingIntent mPushPendingIntent;
 
-    /** Used to end the loadtest. */
+    /**
+     * Used to end the loadtest.
+     */
     private PendingIntent mStopPendingIntent;
 
     private Button mStartStop;
@@ -156,13 +163,19 @@
     private CheckBox mValueMetricCheckBox;
     private CheckBox mGaugeMetricCheckBox;
 
-    /** When the load test started. */
+    /**
+     * When the load test started.
+     */
     private long mStartedTimeMillis;
 
-    /** For measuring perf data. */
+    /**
+     * For measuring perf data.
+     */
     private PerfData mPerfData;
 
-    /** For communicating with statsd. */
+    /**
+     * For communicating with statsd.
+     */
     private StatsManager mStatsManager;
 
     private PowerManager mPowerManager;
@@ -199,34 +212,54 @@
      */
     private boolean mIncludeGaugeMetric;
 
-    /** The burst size. */
+    /**
+     * The burst size.
+     */
     private int mBurst;
 
-    /** The metrics replication. */
+    /**
+     * The metrics replication.
+     */
     private int mReplication;
 
-    /** The period, in seconds, at which batches of atoms are pushed. */
+    /**
+     * The period, in seconds, at which batches of atoms are pushed.
+     */
     private long mPeriodSecs;
 
-    /** The bucket size, in minutes, for aggregate metrics. */
+    /**
+     * The bucket size, in minutes, for aggregate metrics.
+     */
     private TimeUnit mBucket;
 
-    /** The duration, in minutes, of the loadtest. */
+    /**
+     * The duration, in minutes, of the loadtest.
+     */
     private long mDurationMins;
 
-    /** Whether the loadtest has started. */
+    /**
+     * Whether the loadtest has started.
+     */
     private boolean mStarted = false;
 
-    /** Orchestrates the logging of pushed events into logd. */
+    /**
+     * Orchestrates the logging of pushed events into logd.
+     */
     private SequencePusher mPusher;
 
-    /** Generates statsd configs. */
+    /**
+     * Generates statsd configs.
+     */
     private ConfigFactory mFactory;
 
-    /** For intra-minute periods. */
+    /**
+     * For intra-minute periods.
+     */
     private final Handler mHandler = new Handler();
 
-    /** Number of metrics in the current config. */
+    /**
+     * Number of metrics in the current config.
+     */
     private int mNumMetrics;
 
     @Override
@@ -250,7 +283,7 @@
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 InputMethodManager imm =
-                    (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+                        (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                 if (getCurrentFocus() != null) {
                     imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
                 }
@@ -380,10 +413,10 @@
         }
         // Piggy-back on that alarm to show the elapsed time.
         long elapsedTimeMins = (long) Math.floor(
-            (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
+                (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
         mReportText.setText("Loadtest in progress.\n"
-            + "num metrics =" + mNumMetrics
-            + "\nElapsed time = " + elapsedTimeMins + " min(s)");
+                + "num metrics =" + mNumMetrics
+                + "\nElapsed time = " + elapsedTimeMins + " min(s)");
     }
 
     private void onAlarm() {
@@ -402,12 +435,14 @@
         mWakeLock = null;
     }
 
-    /** Schedules the next cycle of pushing atoms into logd. */
+    /**
+     * Schedules the next cycle of pushing atoms into logd.
+     */
     private void scheduleNext() {
         Intent intent = new Intent(this, PusherAlarmReceiver.class);
         intent.putExtra(TYPE, PUSH_ALARM);
         mPushPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
-        long nextTime =  SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
+        long nextTime = SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
         mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mPushPendingIntent);
     }
 
@@ -433,7 +468,7 @@
         Intent intent = new Intent(this, StopperAlarmReceiver.class);
         intent.putExtra(TYPE, STOP);
         mStopPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
-        long nextTime =  SystemClock.elapsedRealtime() + mDurationMins * 60 * 1000;
+        long nextTime = SystemClock.elapsedRealtime() + mDurationMins * 60 * 1000;
         mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mStopPendingIntent);
 
         // Log atoms.
@@ -441,8 +476,8 @@
 
         // Start tracking performance.
         mPerfData = new PerfData(this, mPlacebo, mReplication, mBucket, mPeriodSecs, mBurst,
-            mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric, mIncludeValueMetric,
-            mIncludeGaugeMetric);
+                mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric, mIncludeValueMetric,
+                mIncludeGaugeMetric);
         mPerfData.startRecording(this);
 
         mReportText.setText("Loadtest in progress.\nnum metrics =" + mNumMetrics);
@@ -476,7 +511,7 @@
         getData();
 
         long elapsedTimeMins = (long) Math.floor(
-            (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
+                (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
         mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
         clearConfigs();
         updateStarted(false);
@@ -485,7 +520,7 @@
     private synchronized void updateStarted(boolean started) {
         mStarted = started;
         mStartStop.setBackgroundColor(started ?
-            Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
+                Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
         mStartStop.setText(started ? getString(R.string.stop) : getString(R.string.start));
         updateControlsEnabled();
     }
@@ -538,22 +573,21 @@
     }
 
     private boolean setConfig(ConfigFactory.ConfigMetadata configData) {
-      if (mStatsManager != null) {
-            if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_ID,
-                configData.bytes, getPackageName(), LoadtestActivity.this.getClass().getName())) {
+        if (mStatsManager != null) {
+            if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_ID, configData.bytes)) {
                 mNumMetrics = configData.numMetrics;
                 Log.d(TAG, "Config pushed to statsd");
                 return true;
             } else {
                 Log.d(TAG, "Failed to push config to statsd");
             }
-      }
-      return false;
+        }
+        return false;
     }
 
     private synchronized void setReplication(int replication) {
         if (mStarted) {
-          return;
+            return;
         }
         mReplicationText.setText("" + replication);
     }
@@ -614,13 +648,13 @@
         mBucketSpinner = (Spinner) findViewById(R.id.bucket_spinner);
 
         ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(
-            this, R.layout.spinner_item, TIME_UNIT_LABELS);
+                this, R.layout.spinner_item, TIME_UNIT_LABELS);
 
         mBucketSpinner.setAdapter(dataAdapter);
         mBucketSpinner.setOnItemSelectedListener(this);
 
         for (String label : TIME_UNIT_MAP.keySet()) {
-          if (defaultValue.equals(TIME_UNIT_MAP.get(label).toString())) {
+            if (defaultValue.equals(TIME_UNIT_MAP.get(label).toString())) {
                 mBucketSpinner.setSelection(dataAdapter.getPosition(label));
             }
         }
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index c525c89..88e42d5 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -30,20 +30,26 @@
  * @hide
  */
 @SystemApi
-public final class StatsManager extends android.util.StatsManager { // TODO: Remove the extends.
+public final class StatsManager {
     IStatsManager mService;
     private static final String TAG = "StatsManager";
 
-    /** Long extra of uid that added the relevant stats config. */
-    public static final String EXTRA_STATS_CONFIG_UID =
-            "android.app.extra.STATS_CONFIG_UID";
-    /** Long extra of the relevant stats config's configKey. */
-    public static final String EXTRA_STATS_CONFIG_KEY =
-            "android.app.extra.STATS_CONFIG_KEY";
-    /** Long extra of the relevant statsd_config.proto's Subscription.id. */
+    /**
+     * Long extra of uid that added the relevant stats config.
+     */
+    public static final String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
+    /**
+     * Long extra of the relevant stats config's configKey.
+     */
+    public static final String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
+    /**
+     * Long extra of the relevant statsd_config.proto's Subscription.id.
+     */
     public static final String EXTRA_STATS_SUBSCRIPTION_ID =
             "android.app.extra.STATS_SUBSCRIPTION_ID";
-    /** Long extra of the relevant statsd_config.proto's Subscription.rule_id. */
+    /**
+     * Long extra of the relevant statsd_config.proto's Subscription.rule_id.
+     */
     public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID =
             "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
     /**
@@ -74,12 +80,10 @@
      * @param configKey An arbitrary integer that allows clients to track the configuration.
      * @param config    Wire-encoded StatsDConfig proto that specifies metrics (and all
      *                  dependencies eg, conditions and matchers).
-     * @param pkg       The package name to receive the broadcast.
-     * @param cls       The name of the class that receives the broadcast.
      * @return true if successful
      */
     @RequiresPermission(Manifest.permission.DUMP)
-    public boolean addConfiguration(long configKey, byte[] config, String pkg, String cls) {
+    public boolean addConfiguration(long configKey, byte[] config) {
         synchronized (this) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
@@ -87,7 +91,7 @@
                     Slog.d(TAG, "Failed to find statsd when adding configuration");
                     return false;
                 }
-                return service.addConfiguration(configKey, config, pkg, cls);
+                return service.addConfiguration(configKey, config);
             } catch (RemoteException e) {
                 Slog.d(TAG, "Failed to connect to statsd when adding configuration");
                 return false;
@@ -121,38 +125,34 @@
     /**
      * Set the PendingIntent to be used when broadcasting subscriber information to the given
      * subscriberId within the given config.
-     *
      * <p>
      * Suppose that the calling uid has added a config with key configKey, and that in this config
      * it is specified that when a particular anomaly is detected, a broadcast should be sent to
      * a BroadcastSubscriber with id subscriberId. This function links the given pendingIntent with
      * that subscriberId (for that config), so that this pendingIntent is used to send the broadcast
      * when the anomaly is detected.
-     *
      * <p>
      * When statsd sends the broadcast, the PendingIntent will used to send an intent with
      * information of
-     *   {@link #EXTRA_STATS_CONFIG_UID},
-     *   {@link #EXTRA_STATS_CONFIG_KEY},
-     *   {@link #EXTRA_STATS_SUBSCRIPTION_ID},
-     *   {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID}, and
-     *   {@link #EXTRA_STATS_DIMENSIONS_VALUE}.
-     *
+     * {@link #EXTRA_STATS_CONFIG_UID},
+     * {@link #EXTRA_STATS_CONFIG_KEY},
+     * {@link #EXTRA_STATS_SUBSCRIPTION_ID},
+     * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID}, and
+     * {@link #EXTRA_STATS_DIMENSIONS_VALUE}.
      * <p>
      * This function can only be called by the owner (uid) of the config. It must be called each
      * time statsd starts. The config must have been added first (via addConfiguration()).
      *
-     * @param configKey The integer naming the config to which this subscriber is attached.
-     * @param subscriberId ID of the subscriber, as used in the config.
+     * @param configKey     The integer naming the config to which this subscriber is attached.
+     * @param subscriberId  ID of the subscriber, as used in the config.
      * @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
      *                      associated with the given subscriberId. May be null, in which case
      *                      it undoes any previous setting of this subscriberId.
      * @return true if successful
      */
     @RequiresPermission(Manifest.permission.DUMP)
-    public boolean setBroadcastSubscriber(long configKey,
-                                          long subscriberId,
-                                          PendingIntent pendingIntent) {
+    public boolean setBroadcastSubscriber(
+            long configKey, long subscriberId, PendingIntent pendingIntent) {
         synchronized (this) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
@@ -175,6 +175,44 @@
     }
 
     /**
+     * Registers the operation that is called to retrieve the metrics data. This must be called
+     * each time statsd starts. The config must have been added first (via addConfiguration(),
+     * although addConfiguration could have been called on a previous boot). This operation allows
+     * statsd to send metrics data whenever statsd determines that the metrics in memory are
+     * approaching the memory limits. The fetch operation should call {@link #getData} to fetch the
+     * data, which also deletes the retrieved metrics from statsd's memory.
+     *
+     * @param configKey     The integer naming the config to which this operation is attached.
+     * @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
+     *                      associated with the given subscriberId. May be null, in which case
+     *                      it removes any associated pending intent with this configKey.
+     * @return true if successful
+     */
+    @RequiresPermission(Manifest.permission.DUMP)
+    public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
+        synchronized (this) {
+            try {
+                IStatsManager service = getIStatsManagerLocked();
+                if (service == null) {
+                    Slog.d(TAG, "Failed to find statsd when registering data listener.");
+                    return false;
+                }
+                if (pendingIntent == null) {
+                    return service.removeDataFetchOperation(configKey);
+                } else {
+                    // Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
+                    IBinder intentSender = pendingIntent.getTarget().asBinder();
+                    return service.setDataFetchOperation(configKey, intentSender);
+                }
+
+            } catch (RemoteException e) {
+                Slog.d(TAG, "Failed to connect to statsd when registering data listener.");
+                return false;
+            }
+        }
+    }
+
+    /**
      * Clients can request data with a binder call. This getter is destructive and also clears
      * the retrieved metrics from statsd memory.
      *
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 8a27700..eae5217 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -55,9 +55,8 @@
     /** Pull the specified data. Results will be sent to statsd when complete. */
     StatsLogEventWrapper[] pullData(int pullCode);
 
-    /** Send a broadcast to the specified pkg and class that it should getData now. */
-    // TODO: Rename this and use a pending intent instead.
-    oneway void sendBroadcast(String pkg, String cls);
+    /** Send a broadcast to the specified PendingIntent's as IBinder that it should getData now. */
+    oneway void sendDataBroadcast(in IBinder intentSender);
 
     /**
      * Requests StatsCompanionService to send a broadcast using the given intentSender
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 679b49d..682a24f1 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -81,12 +81,26 @@
     /**
      * Sets a configuration with the specified config key and subscribes to updates for this
      * configuration key. Broadcasts will be sent if this configuration needs to be collected.
-     * The configuration must be a wire-encoded StatsdConfig. The caller specifies the name of the
-     * package and class that should receive these broadcasts.
+     * The configuration must be a wire-encoded StatsDConfig. The receiver for this data is
+     * registered in a separate function.
      *
      * Returns if this configuration was correctly registered.
      */
-    boolean addConfiguration(in long configKey, in byte[] config, in String pkg, in String cls);
+    boolean addConfiguration(in long configKey, in byte[] config);
+
+    /**
+     * Registers the given pending intent for this config key. This intent is invoked when the
+     * memory consumed by the metrics for this configuration approach the pre-defined limits. There
+     * can be at most one listener per config key.
+     *
+     * Returns if this listener was correctly registered.
+     */
+    boolean setDataFetchOperation(long configKey, in IBinder intentSender);
+
+    /**
+     * Removes the data fetch operation for the specified configuration.
+     */
+    boolean removeDataFetchOperation(long configKey);
 
     /**
      * Removes the configuration with the matching config key. No-op if this config key does not
diff --git a/core/java/android/util/StatsManager.java b/core/java/android/util/StatsManager.java
deleted file mode 100644
index 51fb18a..0000000
--- a/core/java/android/util/StatsManager.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.util;
-
-import android.Manifest;
-import android.annotation.RequiresPermission;
-import android.os.IBinder;
-import android.os.IStatsManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-
-
-/*
- *
- *
- *
- *
- * THIS ENTIRE FILE IS ONLY TEMPORARY TO PREVENT BREAKAGES OF DEPENDENCIES ON OLD APIS.
- * The new StatsManager is to be found in android.app.StatsManager.
- * TODO: Delete this file!
- *
- *
- *
- *
- */
-
-
-/**
- * API for StatsD clients to send configurations and retrieve data.
- *
- * @hide
- */
-public class StatsManager {
-    IStatsManager mService;
-    private static final String TAG = "StatsManager";
-
-    /**
-     * Constructor for StatsManagerClient.
-     *
-     * @hide
-     */
-    public StatsManager() {
-    }
-
-    /**
-     * Temporary to prevent build failures. Will be deleted.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public boolean addConfiguration(String configKey, byte[] config, String pkg, String cls) {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when adding configuration");
-                    return false;
-                }
-                return service.addConfiguration(Long.parseLong(configKey), config, pkg, cls);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when adding configuration");
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Clients can send a configuration and simultaneously registers the name of a broadcast
-     * receiver that listens for when it should request data.
-     *
-     * @param configKey An arbitrary integer that allows clients to track the configuration.
-     * @param config    Wire-encoded StatsDConfig proto that specifies metrics (and all
-     *                  dependencies eg, conditions and matchers).
-     * @param pkg       The package name to receive the broadcast.
-     * @param cls       The name of the class that receives the broadcast.
-     * @return true if successful
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public boolean addConfiguration(long configKey, byte[] config, String pkg, String cls) {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when adding configuration");
-                    return false;
-                }
-                return service.addConfiguration(configKey, config, pkg, cls);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when adding configuration");
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Temporary to prevent build failures. Will be deleted.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public boolean removeConfiguration(String configKey) {
-        // To prevent breakages of old dependencies.
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when removing configuration");
-                    return false;
-                }
-                return service.removeConfiguration(Long.parseLong(configKey));
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when removing configuration");
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Remove a configuration from logging.
-     *
-     * @param configKey Configuration key to remove.
-     * @return true if successful
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public boolean removeConfiguration(long configKey) {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when removing configuration");
-                    return false;
-                }
-                return service.removeConfiguration(configKey);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when removing configuration");
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Temporary to prevent build failures. Will be deleted.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public byte[] getData(String configKey) {
-        // TODO: remove this and all other methods with String-based config keys.
-        // To prevent build breakages of dependencies.
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting data");
-                    return null;
-                }
-                return service.getData(Long.parseLong(configKey));
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting data");
-                return null;
-            }
-        }
-    }
-
-    /**
-     * Clients can request data with a binder call. This getter is destructive and also clears
-     * the retrieved metrics from statsd memory.
-     *
-     * @param configKey Configuration key to retrieve data from.
-     * @return Serialized ConfigMetricsReportList proto. Returns null on failure.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public byte[] getData(long configKey) {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting data");
-                    return null;
-                }
-                return service.getData(configKey);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting data");
-                return null;
-            }
-        }
-    }
-
-    /**
-     * Clients can request metadata for statsd. Will contain stats across all configurations but not
-     * the actual metrics themselves (metrics must be collected via {@link #getData(String)}.
-     * This getter is not destructive and will not reset any metrics/counters.
-     *
-     * @return Serialized StatsdStatsReport proto. Returns null on failure.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public byte[] getMetadata() {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting metadata");
-                    return null;
-                }
-                return service.getMetadata();
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting metadata");
-                return null;
-            }
-        }
-    }
-
-    private class StatsdDeathRecipient implements IBinder.DeathRecipient {
-        @Override
-        public void binderDied() {
-            synchronized (this) {
-                mService = null;
-            }
-        }
-    }
-
-    private IStatsManager getIStatsManagerLocked() throws RemoteException {
-        if (mService != null) {
-            return mService;
-        }
-        mService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
-        if (mService != null) {
-            mService.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
-        }
-        return mService;
-    }
-}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index a87ae1e..a82b559 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -87,9 +87,7 @@
     static final String TAG = "StatsCompanionService";
     static final boolean DEBUG = true;
 
-    public static final String ACTION_TRIGGER_COLLECTION =
-        "com.android.server.stats.action.TRIGGER_COLLECTION";
-
+    public static final int CODE_DATA_BROADCAST = 1;
     public static final int CODE_SUBSCRIBER_BROADCAST = 1;
 
     private final Context mContext;
@@ -110,9 +108,9 @@
     private TelephonyManager mTelephony = null;
     private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
     private final StatFs mStatFsSystem =
-        new StatFs(Environment.getRootDirectory().getAbsolutePath());
+            new StatFs(Environment.getRootDirectory().getAbsolutePath());
     private final StatFs mStatFsTemp =
-        new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
+            new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
 
     public StatsCompanionService(Context context) {
         super();
@@ -122,7 +120,7 @@
         mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
                 new Intent(mContext, AnomalyAlarmReceiver.class), 0);
         mPullingAlarmIntent = PendingIntent.getBroadcast(
-            mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
+                mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
         mAppUpdateReceiver = new AppUpdateReceiver();
         mUserUpdateReceiver = new BroadcastReceiver() {
             @Override
@@ -153,17 +151,21 @@
         for (int i = 0; i < numClusters; i++) {
             final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i);
             mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
-                            numSpeedSteps);
+                    numSpeedSteps);
             firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i);
         }
     }
 
     @Override
-    public void sendBroadcast(String pkg, String cls) {
-        // TODO: Use a pending intent.
+    public void sendDataBroadcast(IBinder intentSenderBinder) {
         enforceCallingPermission();
-        mContext.sendBroadcastAsUser(new Intent(ACTION_TRIGGER_COLLECTION).setClassName(pkg, cls),
-                UserHandle.SYSTEM);
+        IntentSender intentSender = new IntentSender(intentSenderBinder);
+        Intent intent = new Intent();
+        try {
+            intentSender.sendIntent(mContext, CODE_DATA_BROADCAST, intent, null, null);
+        } catch (IntentSender.SendIntentException e) {
+            Slog.w(TAG, "Unable to send using IntentSender");
+        }
     }
 
     @Override
@@ -305,24 +307,23 @@
     }
 
     public final static class PullingAlarmReceiver extends BroadcastReceiver {
-      @Override
-      public void onReceive(Context context, Intent intent) {
-        if (DEBUG)
-          Slog.d(TAG, "Time to poll something.");
-        synchronized (sStatsdLock) {
-          if (sStatsd == null) {
-            Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
-            return;
-          }
-          try {
-            // Two-way call to statsd to retain AlarmManager wakelock
-            sStatsd.informPollAlarmFired();
-          } catch (RemoteException e) {
-            Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
-          }
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG)
+                Slog.d(TAG, "Time to poll something.");
+            synchronized (sStatsdLock) {
+                if (sStatsd == null) {
+                    Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
+                    return;
+                }
+                try {
+                    // Two-way call to statsd to retain AlarmManager wakelock
+                    sStatsd.informPollAlarmFired();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
+                }
+            }
         }
-        // AlarmManager releases its own wakelock here.
-      }
     }
 
     private final static class ShutdownEventReceiver extends BroadcastReceiver {
@@ -332,9 +333,9 @@
              * Skip immediately if intent is not relevant to device shutdown.
              */
             if (!intent.getAction().equals(Intent.ACTION_REBOOT)
-                && !(intent.getAction().equals(Intent.ACTION_SHUTDOWN)
-                       && (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0)) {
-              return;
+                    && !(intent.getAction().equals(Intent.ACTION_SHUTDOWN)
+                    && (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0)) {
+                return;
             }
 
             Slog.i(TAG, "StatsCompanionService noticed a shutdown.");
@@ -381,50 +382,50 @@
 
     @Override // Binder call
     public void setPullingAlarms(long timestampMs, long intervalMs) {
-      enforceCallingPermission();
-      if (DEBUG)
-        Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
-      final long callingToken = Binder.clearCallingIdentity();
-      try {
-        // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
-        // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
-        // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
-        mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
-      } finally {
-        Binder.restoreCallingIdentity(callingToken);
-      }
+        enforceCallingPermission();
+        if (DEBUG)
+            Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+            // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
+            mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
     }
 
     @Override // Binder call
     public void cancelPullingAlarms() {
-      enforceCallingPermission();
-      if (DEBUG)
-        Slog.d(TAG, "Cancelling pulling alarm");
-      final long callingToken = Binder.clearCallingIdentity();
-      try {
-        mAlarmManager.cancel(mPullingAlarmIntent);
-      } finally {
-        Binder.restoreCallingIdentity(callingToken);
-      }
+        enforceCallingPermission();
+        if (DEBUG)
+            Slog.d(TAG, "Cancelling pulling alarm");
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            mAlarmManager.cancel(mPullingAlarmIntent);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
     }
 
     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);
+            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);
+            }
+            e.writeLong(entry.rxBytes);
+            e.writeLong(entry.rxPackets);
+            e.writeLong(entry.txBytes);
+            e.writeLong(entry.txPackets);
+            ret.add(e);
         }
-        e.writeLong(entry.rxBytes);
-        e.writeLong(entry.rxPackets);
-        e.writeLong(entry.txBytes);
-        e.writeLong(entry.txPackets);
-        ret.add(e);
-      }
     }
 
     /**
@@ -491,220 +492,220 @@
     }
 
     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);
-      }
+        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;
+        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);
         }
-        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;
+        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);
         }
-        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;
+        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);
         }
-        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);
-      }
+        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;
+        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);
         }
-        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);
-          }
+        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);
+        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);
-      }
+        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);
+        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() {
         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-      if (adapter != null) {
-        SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
-        adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
-        return awaitControllerInfo(bluetoothReceiver);
-      } else {
-          Slog.e(TAG, "Failed to get bluetooth adapter!");
-        return null;
-      }
+        if (adapter != null) {
+            SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
+            adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+            return awaitControllerInfo(bluetoothReceiver);
+        } else {
+            Slog.e(TAG, "Failed to get bluetooth adapter!");
+            return null;
+        }
     }
 
     private void pullSystemElapsedRealtime(int tagId, List<StatsLogEventWrapper> pulledData) {
-      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
-      e.writeLong(SystemClock.elapsedRealtime());
-      pulledData.add(e);
+        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);
+        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);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
+        e.writeLong(SystemClock.uptimeMillis());
+        pulledData.add(e);
     }
 
     /**
@@ -718,56 +719,56 @@
         List<StatsLogEventWrapper> ret = new ArrayList();
         switch (tagId) {
             case StatsLog.WIFI_BYTES_TRANSFER: {
-              pullWifiBytesTransfer(tagId, ret);
-              break;
+                pullWifiBytesTransfer(tagId, ret);
+                break;
             }
             case StatsLog.MOBILE_BYTES_TRANSFER: {
-              pullMobileBytesTransfer(tagId, ret);
-              break;
+                pullMobileBytesTransfer(tagId, ret);
+                break;
             }
             case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
-              pullWifiBytesTransferByFgBg(tagId, ret);
-              break;
+                pullWifiBytesTransferByFgBg(tagId, ret);
+                break;
             }
             case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
-              pullMobileBytesTransferByFgBg(tagId, ret);
-              break;
+                pullMobileBytesTransferByFgBg(tagId, ret);
+                break;
             }
             case StatsLog.BLUETOOTH_BYTES_TRANSFER: {
-              pullBluetoothBytesTransfer(tagId, ret);
-              break;
+                pullBluetoothBytesTransfer(tagId, ret);
+                break;
             }
             case StatsLog.KERNEL_WAKELOCK: {
-              pullKernelWakelock(tagId, ret);
-              break;
+                pullKernelWakelock(tagId, ret);
+                break;
             }
             case StatsLog.CPU_TIME_PER_FREQ: {
-              pullCpuTimePerFreq(tagId, ret);
-              break;
+                pullCpuTimePerFreq(tagId, ret);
+                break;
             }
             case StatsLog.WIFI_ACTIVITY_ENERGY_INFO: {
-              pullWifiActivityEnergyInfo(tagId, ret);
-              break;
+                pullWifiActivityEnergyInfo(tagId, ret);
+                break;
             }
             case StatsLog.MODEM_ACTIVITY_INFO: {
-              pullModemActivityInfo(tagId, ret);
-              break;
+                pullModemActivityInfo(tagId, ret);
+                break;
             }
             case StatsLog.BLUETOOTH_ACTIVITY_INFO: {
-              pullBluetoothActivityInfo(tagId, ret);
-              break;
+                pullBluetoothActivityInfo(tagId, ret);
+                break;
             }
             case StatsLog.SYSTEM_UPTIME: {
-              pullSystemUpTime(tagId, ret);
-              break;
+                pullSystemUpTime(tagId, ret);
+                break;
             }
             case StatsLog.SYSTEM_ELAPSED_REALTIME: {
-              pullSystemElapsedRealtime(tagId, ret);
-              break;
+                pullSystemElapsedRealtime(tagId, ret);
+                break;
             }
             case StatsLog.DISK_SPACE: {
-              pullDiskSpace(tagId, ret);
-              break;
+                pullDiskSpace(tagId, ret);
+                break;
             }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
@@ -788,14 +789,14 @@
 
     @Override
     public void triggerUidSnapshot() {
-      enforceCallingPermission();
-      synchronized (sStatsdLock) {
-        try {
-          informAllUidsLocked(mContext);
-        } catch (RemoteException e) {
-          Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+        enforceCallingPermission();
+        synchronized (sStatsdLock) {
+            try {
+                informAllUidsLocked(mContext);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+            }
         }
-      }
     }
 
     private void enforceCallingPermission() {