Adds client API for interacting with statsd.
This API will primarily be used by GmsCore to send updated configs.
Also, sending a config will implicitly notify the StatsD that this
client wants to know when it should request data for this config.
We send a broadcast so that all interested subscribers can know if
data needs to be pulled.
Test: Manually tested that sending broadcast works via new adb
command added in StatsService.
Change-Id: I23cdd1df706036e14b32c3d01af30c3d4af819fa
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d813d66..e48946f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -137,6 +137,7 @@
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccManager;
import android.util.Log;
+import android.util.StatsManager;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.WindowManager;
@@ -452,6 +453,13 @@
ctx.mMainThread.getHandler().getLooper());
}});
+ registerService(Context.STATS_MANAGER, StatsManager.class,
+ new StaticServiceFetcher<StatsManager>() {
+ @Override
+ public StatsManager createService() throws ServiceNotFoundException {
+ return new StatsManager();
+ }});
+
registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
new CachedServiceFetcher<StatusBarManager>() {
@Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 72f75112..19e24ad 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4044,6 +4044,13 @@
public static final String STATS_COMPANION_SERVICE = "statscompanion";
/**
+ * Use with {@link #getSystemService} to retrieve an {@link android.stats.StatsManager}.
+ * @hide
+ */
+ @SystemApi
+ public static final String STATS_MANAGER = "stats";
+
+ /**
* Use with {@link #getSystemService} to retrieve a {@link
* android.content.om.OverlayManager} for managing overlay packages.
*
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index c0a95cc..3314f60 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -53,4 +53,7 @@
/** 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. */
+ oneway void sendBroadcast(String pkg, String cls);
}
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 480296c..a6c3009 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -65,13 +65,26 @@
oneway void informOnePackageRemoved(in String app, in int uid);
/**
- * Trigger pushLog to force push stats log entries from statsd on client side.
+ * Fetches data for the specified configuration key. Returns a byte array representing proto
+ * wire-encoded of ConfigMetricsReport.
*/
- void requestPush();
+ byte[] getData(in String key);
/**
- * Listen to statsd to send stats log entries.
- * TODO: Limit callbacks with specific configurations.
+ * 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.
+ *
+ * Returns if this configuration was correctly registered.
*/
- void subscribeStatsLog(IStatsCallbacks callbacks);
+ boolean addConfiguration(in String configKey, in byte[] config, in String pkg, in String cls);
+
+ /**
+ * Removes the configuration with the matching config key. No-op if this config key does not
+ * exist.
+ *
+ * Returns if this configuration key was removed.
+ */
+ boolean removeConfiguration(in String configKey);
}
diff --git a/core/java/android/util/StatsManager.java b/core/java/android/util/StatsManager.java
new file mode 100644
index 0000000..55b33a6
--- /dev/null
+++ b/core/java/android/util/StatsManager.java
@@ -0,0 +1,134 @@
+/*
+ * 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.annotation.SystemApi;
+import android.os.IBinder;
+import android.os.IStatsManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * API for StatsD clients to send configurations and retrieve data.
+ *
+ * @hide
+ */
+@SystemApi
+public final class StatsManager {
+ IStatsManager mService;
+ private static final String TAG = "StatsManager";
+
+ /**
+ * Constructor for StatsManagerClient.
+ *
+ * @hide
+ */
+ public StatsManager() {
+ }
+
+ /**
+ * 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 string 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(String configKey, byte[] config, String pkg, String cls) {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (service == null) {
+ throw new RuntimeException("StatsD service connection lost");
+ }
+ return service.addConfiguration(configKey, config, pkg, cls);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Failed to connect to statsd when getting data");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Remove a configuration from logging.
+ *
+ * @param configKey Configuration key to remove.
+ * @return true if successful
+ */
+ @RequiresPermission(Manifest.permission.DUMP)
+ public boolean removeConfiguration(String configKey) {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (service == null) {
+ throw new RuntimeException("StatsD service connection lost");
+ }
+ return service.removeConfiguration(configKey);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Failed to connect to statsd when getting data");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Clients can request data with a binder call.
+ *
+ * @param configKey Configuration key to retrieve data from.
+ * @return Serialized ConfigMetricsReport proto. Returns null on failure.
+ */
+ @RequiresPermission(Manifest.permission.DUMP)
+ public byte[] getData(String configKey) {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (service == null) {
+ throw new RuntimeException("StatsD service connection lost");
+ }
+ return service.getData(configKey);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Failed to connecto statsd when getting data");
+ 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/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7af1b46..f257d5e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -307,6 +307,8 @@
<protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" />
<protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
+ <protected-broadcast android:name="com.android.server.stats.action.TRIGGER_COLLECTION" />
+
<protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
<protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />