Merge changes I1510e44b,I9313299e,I7df5c644

* changes:
  Update setBroadcastSubscriber
  Update activeConfigsChangedBroadcast
  Creating PendingIntentRef
This commit is contained in:
Jeffrey Huang
2020-01-07 02:18:22 +00:00
committed by Android (Google) Code Review
15 changed files with 694 additions and 316 deletions

View File

@@ -18,6 +18,7 @@
filegroup {
name: "statsd_aidl",
srcs: [
"android/os/IPendingIntentRef.aidl",
"android/os/IPullAtomCallback.aidl",
"android/os/IPullAtomResultReceiver.aidl",
"android/os/IStatsCompanionService.aidl",

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2019 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.os;
import android.os.StatsDimensionsValue;
/**
* Binder interface to hold a PendingIntent for StatsCompanionService.
* {@hide}
*/
interface IPendingIntentRef {
/**
* Sends a broadcast to the specified PendingIntent that it should getData now.
* This should be only called from StatsCompanionService.
*/
oneway void sendDataBroadcast(long lastReportTimeNs);
/**
* Send a broadcast to the specified PendingIntent notifying it that the list of active configs
* has changed. This should be only called from StatsCompanionService.
*/
oneway void sendActiveConfigsChangedBroadcast(in long[] configIds);
/**
* Send a broadcast to the specified PendingIntent, along with the other information
* specified. This should only be called from StatsCompanionService.
*/
oneway void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
long subscriptionRuleId, in String[] cookies,
in StatsDimensionsValue dimensionsValue);
}

View File

@@ -17,7 +17,6 @@
package android.os;
import android.os.IPullAtomCallback;
import android.os.StatsDimensionsValue;
import android.os.StatsLogEventWrapper;
/**
@@ -66,24 +65,6 @@ interface IStatsCompanionService {
/** Pull the specified data. Results will be sent to statsd when complete. */
StatsLogEventWrapper[] pullData(int pullCode);
/** Send a broadcast to the specified PendingIntent's as IBinder that it should getData now. */
oneway void sendDataBroadcast(in IBinder intentSender, long lastReportTimeNs);
/**
* Send a broadcast to the specified PendingIntent's as IBinder notifying it that the list
* of active configs has changed.
*/
oneway void sendActiveConfigsChangedBroadcast(in IBinder intentSender, in long[] configIds);
/**
* Requests StatsCompanionService to send a broadcast using the given intentSender
* (which should cast to an IIntentSender), along with the other information specified.
*/
oneway void sendSubscriberBroadcast(in IBinder intentSender, long configUid, long configId,
long subscriptionId, long subscriptionRuleId,
in String[] cookies,
in StatsDimensionsValue dimensionsValue);
/** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
oneway void triggerUidSnapshot();

View File

@@ -30,11 +30,18 @@ interface IStatsManagerService {
* memory consumed by the metrics for this configuration approach the pre-defined limits. There
* can be at most one listener per config key.
*
* Requires Manifest.permission.DUMP.
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void setDataFetchOperation(long configKey, in PendingIntent pendingIntent,
void setDataFetchOperation(long configId, in PendingIntent pendingIntent,
in String packageName);
/**
* Removes the data fetch operation for the specified configuration.
*
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void removeDataFetchOperation(long configId, in String packageName);
/**
* Registers the given pending intent for this packagename. This intent is invoked when the
* active status of any of the configs sent by this package changes and will contain a list of
@@ -45,6 +52,13 @@ interface IStatsManagerService {
*/
long[] setActiveConfigsChangedOperation(in PendingIntent pendingIntent, in String packageName);
/**
* Removes the active configs changed operation for the specified package name.
*
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void removeActiveConfigsChangedOperation(in String packageName);
/**
* Set the PendingIntent to be used when broadcasting subscriber
* information to the given subscriberId within the given config.
@@ -58,8 +72,17 @@ interface IStatsManagerService {
* This function can only be called by the owner (uid) of the config. It must be called each
* time statsd starts. Later calls overwrite previous calls; only one PendingIntent is stored.
*
* Requires Manifest.permission.DUMP.
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void setBroadcastSubscriber(long configKey, long subscriberId, in PendingIntent pendingIntent,
in String packageName);
/**
* Undoes setBroadcastSubscriber() for the (configKey, subscriberId) pair.
* Any broadcasts associated with subscriberId will henceforth not be sent.
* No-op if this (configKey, subscriberId) pair was not associated with an PendingIntent.
*
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
}

View File

@@ -17,6 +17,7 @@
package android.os;
import android.os.IStatsPullerCallback;
import android.os.IPendingIntentRef;
import android.os.IPullAtomCallback;
import android.os.ParcelFileDescriptor;
@@ -114,14 +115,15 @@ interface IStatsd {
*
* Requires Manifest.permission.DUMP.
*/
void setDataFetchOperation(long configKey, in IBinder intentSender, in String packageName);
void setDataFetchOperation(long configId, in IPendingIntentRef pendingIntentRef,
int callingUid);
/**
* Removes the data fetch operation for the specified configuration.
*
* Requires Manifest.permission.DUMP.
*/
void removeDataFetchOperation(long configKey, in String packageName);
void removeDataFetchOperation(long configId, int callingUid);
/**
* Registers the given pending intent for this packagename. This intent is invoked when the
@@ -131,14 +133,14 @@ interface IStatsd {
*
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
long[] setActiveConfigsChangedOperation(in IBinder intentSender, in String packageName);
long[] setActiveConfigsChangedOperation(in IPendingIntentRef pendingIntentRef, int callingUid);
/**
* Removes the active configs changed operation for the specified package name.
*
* Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
*/
void removeActiveConfigsChangedOperation(in String packageName);
void removeActiveConfigsChangedOperation(int callingUid);
/**
* Removes the configuration with the matching config key. No-op if this config key does not
@@ -149,34 +151,31 @@ interface IStatsd {
void removeConfiguration(in long configKey, in String packageName);
/**
* Set the IIntentSender (i.e. PendingIntent) to be used when broadcasting subscriber
* Set the PendingIntentRef to be used when broadcasting subscriber
* information to the given subscriberId within the given config.
*
* Suppose that the calling uid has added a config with key configKey, and that in this config
* Suppose that the calling uid has added a config with key configId, 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 intentSender with
* that subscriberId (for that config), so that this intentSender is used to send the broadcast
* 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.
*
* This function can only be called by the owner (uid) of the config. It must be called each
* time statsd starts. Later calls overwrite previous calls; only one intentSender is stored.
*
* intentSender must be convertible into an IntentSender using IntentSender(IBinder)
* and cannot be null.
* time statsd starts. Later calls overwrite previous calls; only one pendingIntent is stored.
*
* Requires Manifest.permission.DUMP.
*/
void setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender,
in String packageName);
void setBroadcastSubscriber(long configId, long subscriberId, in IPendingIntentRef pir,
int callingUid);
/**
* Undoes setBroadcastSubscriber() for the (configKey, subscriberId) pair.
* Undoes setBroadcastSubscriber() for the (configId, subscriberId) pair.
* Any broadcasts associated with subscriberId will henceforth not be sent.
* No-op if this (configKey, subsriberId) pair was not associated with an IntentSender.
* No-op if this (configKey, subscriberId) pair was not associated with an PendingIntentRef.
*
* Requires Manifest.permission.DUMP.
*/
void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
void unsetBroadcastSubscriber(long configId, long subscriberId, int callingUid);
/**
* Apps can send an atom via this application breadcrumb with the specified label and state for

View File

@@ -16,11 +16,21 @@
package com.android.server.stats;
import android.app.PendingIntent;
import android.app.StatsManager;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IPendingIntentRef;
import android.os.Process;
import android.os.StatsDimensionsValue;
import android.util.Slog;
import com.android.server.SystemService;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @hide
*/
@@ -28,6 +38,13 @@ public class StatsCompanion {
private static final String TAG = "StatsCompanion";
private static final boolean DEBUG = false;
static void enforceStatsCompanionPermission(Context context) {
if (Binder.getCallingPid() == Process.myPid()) {
return;
}
context.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
}
/**
* Lifecycle class for both {@link StatsCompanionService} and {@link StatsManagerService}.
*/
@@ -63,7 +80,97 @@ public class StatsCompanion {
super.onBootPhase(phase);
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
mStatsCompanionService.systemReady();
mStatsManagerService.systemReady();
}
}
}
/**
* Wrapper for {@link PendingIntent}. Allows Statsd to send PendingIntents.
*/
public static class PendingIntentRef extends IPendingIntentRef.Stub {
private static final String TAG = "PendingIntentRef";
/**
* The last report time is provided with each intent registered to
* StatsManager#setFetchReportsOperation. This allows easy de-duping in the receiver if
* statsd is requesting the client to retrieve the same statsd data. The last report time
* corresponds to the last_report_elapsed_nanos that will provided in the current
* ConfigMetricsReport, and this timestamp also corresponds to the
* current_report_elapsed_nanos of the most recently obtained ConfigMetricsReport.
*/
private static final String EXTRA_LAST_REPORT_TIME = "android.app.extra.LAST_REPORT_TIME";
private static final int CODE_DATA_BROADCAST = 1;
private static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1;
private static final int CODE_SUBSCRIBER_BROADCAST = 1;
private final PendingIntent mPendingIntent;
private final Context mContext;
public PendingIntentRef(PendingIntent pendingIntent, Context context) {
mPendingIntent = pendingIntent;
mContext = context;
}
@Override
public void sendDataBroadcast(long lastReportTimeNs) {
enforceStatsCompanionPermission(mContext);
Intent intent = new Intent();
intent.putExtra(EXTRA_LAST_REPORT_TIME, lastReportTimeNs);
try {
mPendingIntent.send(mContext, CODE_DATA_BROADCAST, intent, null, null);
} catch (PendingIntent.CanceledException e) {
Slog.w(TAG, "Unable to send PendingIntent");
}
}
@Override
public void sendActiveConfigsChangedBroadcast(long[] configIds) {
enforceStatsCompanionPermission(mContext);
Intent intent = new Intent();
intent.putExtra(StatsManager.EXTRA_STATS_ACTIVE_CONFIG_KEYS, configIds);
try {
mPendingIntent.send(mContext, CODE_ACTIVE_CONFIGS_BROADCAST, intent, null, null);
if (DEBUG) {
Slog.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
}
} catch (PendingIntent.CanceledException e) {
Slog.w(TAG, "Unable to send active configs changed broadcast using PendingIntent");
}
}
@Override
public void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
long subscriptionRuleId, String[] cookies, StatsDimensionsValue dimensionsValue) {
enforceStatsCompanionPermission(mContext);
Intent intent =
new Intent()
.putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
.putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configId)
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID,
subscriptionRuleId)
.putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
ArrayList<String> cookieList = new ArrayList<>(cookies.length);
cookieList.addAll(Arrays.asList(cookies));
intent.putStringArrayListExtra(
StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
if (DEBUG) {
Slog.d(TAG,
String.format(
"Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
configUid, configId, subscriptionId, subscriptionRuleId,
Arrays.toString(cookies),
dimensionsValue));
}
try {
mPendingIntent.send(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
} catch (PendingIntent.CanceledException e) {
Slog.w(TAG,
"Unable to send using PendingIntent from uid " + configUid
+ "; presumably it had been cancelled.");
}
}
}

View File

@@ -50,7 +50,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -85,11 +84,9 @@ import android.os.IThermalService;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.Process;
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;
@@ -203,18 +200,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private static final int PACKAGE_NAME_FIELD_ID = 4;
private static final int INSTALLER_FIELD_ID = 5;
public static final int CODE_DATA_BROADCAST = 1;
public static final int CODE_SUBSCRIBER_BROADCAST = 1;
public static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1;
/**
* The last report time is provided with each intent registered to
* StatsManager#setFetchReportsOperation. This allows easy de-duping in the receiver if
* statsd is requesting the client to retrieve the same statsd data. The last report time
* corresponds to the last_report_elapsed_nanos that will provided in the current
* ConfigMetricsReport, and this timestamp also corresponds to the
* current_report_elapsed_nanos of the most recently obtained ConfigMetricsReport.
*/
public static final String EXTRA_LAST_REPORT_TIME = "android.app.extra.LAST_REPORT_TIME";
public static final int DEATH_THRESHOLD = 10;
/**
* Which native processes to snapshot memory for.
@@ -454,72 +439,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext);
}
@Override
public void sendDataBroadcast(IBinder intentSenderBinder, long lastReportTimeNs) {
enforceCallingPermission();
IntentSender intentSender = new IntentSender(intentSenderBinder);
Intent intent = new Intent();
intent.putExtra(EXTRA_LAST_REPORT_TIME, lastReportTimeNs);
try {
intentSender.sendIntent(mContext, CODE_DATA_BROADCAST, intent, null, null);
} catch (IntentSender.SendIntentException e) {
Slog.w(TAG, "Unable to send using IntentSender");
}
}
@Override
public void sendActiveConfigsChangedBroadcast(IBinder intentSenderBinder, long[] configIds) {
enforceCallingPermission();
IntentSender intentSender = new IntentSender(intentSenderBinder);
Intent intent = new Intent();
intent.putExtra(StatsManager.EXTRA_STATS_ACTIVE_CONFIG_KEYS, configIds);
try {
intentSender.sendIntent(mContext, CODE_ACTIVE_CONFIGS_BROADCAST, intent, null, null);
if (DEBUG) {
Slog.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
}
} catch (IntentSender.SendIntentException e) {
Slog.w(TAG, "Unable to send active configs changed broadcast using IntentSender");
}
}
@Override
public void sendSubscriberBroadcast(IBinder intentSenderBinder, long configUid, long configKey,
long subscriptionId, long subscriptionRuleId, String[] cookies,
StatsDimensionsValue dimensionsValue) {
enforceCallingPermission();
IntentSender intentSender = new IntentSender(intentSenderBinder);
Intent intent =
new Intent()
.putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
.putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configKey)
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
.putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID, subscriptionRuleId)
.putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
ArrayList<String> cookieList = new ArrayList<>(cookies.length);
for (String cookie : cookies) {
cookieList.add(cookie);
}
intent.putStringArrayListExtra(
StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
if (DEBUG) {
Slog.d(TAG,
String.format("Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
configUid, configKey, subscriptionId, subscriptionRuleId,
Arrays.toString(cookies),
dimensionsValue));
}
try {
intentSender.sendIntent(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
} catch (IntentSender.SendIntentException e) {
Slog.w(TAG,
"Unable to send using IntentSender from uid " + configUid
+ "; presumably it had been cancelled.");
}
}
private final static int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
for (int i = 0; i < ret.length; i++) {
@@ -770,7 +689,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override // Binder call
public void setAnomalyAlarm(long timestampMs) {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
final long callingToken = Binder.clearCallingIdentity();
try {
@@ -786,7 +705,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override // Binder call
public void cancelAnomalyAlarm() {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
final long callingToken = Binder.clearCallingIdentity();
try {
@@ -798,7 +717,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override // Binder call
public void setAlarmForSubscriberTriggering(long timestampMs) {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
if (DEBUG) {
Slog.d(TAG,
"Setting periodic alarm in about " + (timestampMs
@@ -817,7 +736,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override // Binder call
public void cancelAlarmForSubscriberTriggering() {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
if (DEBUG) {
Slog.d(TAG, "Cancelling periodic alarm");
}
@@ -831,7 +750,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override // Binder call
public void setPullingAlarm(long nextPullTimeMs) {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
if (DEBUG) {
Slog.d(TAG, "Setting pulling alarm in about "
+ (nextPullTimeMs - SystemClock.elapsedRealtime()));
@@ -849,7 +768,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override // Binder call
public void cancelPullingAlarm() {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
if (DEBUG) {
Slog.d(TAG, "Cancelling pulling alarm");
}
@@ -2455,7 +2374,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
*/
@Override // Binder call
public StatsLogEventWrapper[] pullData(int tagId) {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
if (DEBUG) {
Slog.d(TAG, "Pulling " + tagId);
}
@@ -2690,12 +2609,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override // Binder call
public void statsdReady() {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
if (DEBUG) {
Slog.d(TAG, "learned that statsdReady");
}
sayHiToStatsd(); // tell statsd that we're ready too and link to it
mStatsManagerService.systemReady();
mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED)
.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
UserHandle.SYSTEM, android.Manifest.permission.DUMP);
@@ -2703,7 +2621,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
@Override
public void triggerUidSnapshot() {
enforceCallingPermission();
StatsCompanion.enforceStatsCompanionPermission(mContext);
synchronized (sStatsdLock) {
final long token = Binder.clearCallingIdentity();
try {
@@ -2716,13 +2634,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
private void enforceCallingPermission() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
}
mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
}
@Override
public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
int[] additiveFields, IPullAtomCallback pullerCallback) {
@@ -2817,6 +2728,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
+ "alive.");
return;
}
mStatsManagerService.statsdReady(sStatsd);
if (DEBUG) Slog.d(TAG, "Saying hi to statsd");
try {
sStatsd.statsCompanionReady();
@@ -2928,6 +2840,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
if (looperStats != null) {
looperStats.reset();
}
mStatsManagerService.statsdNotReady();
}
@Override

View File

@@ -16,18 +16,28 @@
package com.android.server.stats;
import static com.android.server.stats.StatsCompanion.PendingIntentRef;
import android.Manifest;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.Context;
import android.os.IBinder;
import android.os.Binder;
import android.os.IStatsManagerService;
import android.os.IStatsd;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import java.util.Map;
import java.util.Objects;
/**
* Service for {@link android.app.StatsManager}.
*
* @hide
*/
public class StatsManagerService extends IStatsManagerService.Stub {
@@ -35,41 +45,203 @@ public class StatsManagerService extends IStatsManagerService.Stub {
private static final String TAG = "StatsManagerService";
private static final boolean DEBUG = false;
@GuardedBy("sStatsdLock")
private static IStatsd sStatsd;
private static final Object sStatsdLock = new Object();
private static final int STATSD_TIMEOUT_MILLIS = 5000;
private static final String USAGE_STATS_PERMISSION_OPS = "android:get_usage_stats";
@GuardedBy("mLock")
private IStatsd mStatsd;
private final Object mLock = new Object();
private StatsCompanionService mStatsCompanionService;
private Context mContext;
@GuardedBy("mLock")
private ArrayMap<ConfigKey, PendingIntentRef> mDataFetchPirMap = new ArrayMap<>();
@GuardedBy("mLock")
private ArrayMap<Integer, PendingIntentRef> mActiveConfigsPirMap =
new ArrayMap<>();
@GuardedBy("mLock")
private ArrayMap<ConfigKey, ArrayMap<Long, PendingIntentRef>> mBroadcastSubscriberPirMap =
new ArrayMap<>();
public StatsManagerService(Context context) {
super();
mContext = context;
}
private static class ConfigKey {
private int mUid;
private long mConfigId;
ConfigKey(int uid, long configId) {
mUid = uid;
mConfigId = configId;
}
public int getUid() {
return mUid;
}
public long getConfigId() {
return mConfigId;
}
@Override
public int hashCode() {
return Objects.hash(mUid, mConfigId);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ConfigKey) {
ConfigKey other = (ConfigKey) obj;
return this.mUid == other.getUid() && this.mConfigId == other.getConfigId();
}
return false;
}
}
@Override
public void setDataFetchOperation(long configKey, PendingIntent pendingIntent,
public void setDataFetchOperation(long configId, PendingIntent pendingIntent,
String packageName) {
// no-op
if (DEBUG) {
Slog.d(TAG, "setDataFetchOperation");
enforceDumpAndUsageStatsPermission(packageName);
int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
PendingIntentRef pir = new PendingIntentRef(pendingIntent, mContext);
ConfigKey key = new ConfigKey(callingUid, configId);
// We add the PIR to a map so we can reregister if statsd is unavailable.
synchronized (mLock) {
mDataFetchPirMap.put(key, pir);
}
try {
IStatsd statsd = getStatsdNonblocking();
if (statsd != null) {
statsd.setDataFetchOperation(configId, pir, callingUid);
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setDataFetchOperation with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void removeDataFetchOperation(long configId, String packageName) {
enforceDumpAndUsageStatsPermission(packageName);
int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
ConfigKey key = new ConfigKey(callingUid, configId);
synchronized (mLock) {
mDataFetchPirMap.remove(key);
}
try {
IStatsd statsd = getStatsdNonblocking();
if (statsd != null) {
statsd.removeDataFetchOperation(configId, callingUid);
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to removeDataFetchOperation with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public long[] setActiveConfigsChangedOperation(PendingIntent pendingIntent,
String packageName) {
// no-op
if (DEBUG) {
Slog.d(TAG, "setActiveConfigsChangedOperation");
enforceDumpAndUsageStatsPermission(packageName);
int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
PendingIntentRef pir = new PendingIntentRef(pendingIntent, mContext);
// We add the PIR to a map so we can reregister if statsd is unavailable.
synchronized (mLock) {
mActiveConfigsPirMap.put(callingUid, pir);
}
return new long[]{};
try {
IStatsd statsd = getStatsdNonblocking();
if (statsd != null) {
return statsd.setActiveConfigsChangedOperation(pir, callingUid);
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setActiveConfigsChangedOperation with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
return new long[] {};
}
@Override
public void setBroadcastSubscriber(long configKey, long subscriberId,
public void removeActiveConfigsChangedOperation(String packageName) {
enforceDumpAndUsageStatsPermission(packageName);
int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
synchronized (mLock) {
mActiveConfigsPirMap.remove(callingUid);
}
try {
IStatsd statsd = getStatsdNonblocking();
if (statsd != null) {
statsd.removeActiveConfigsChangedOperation(callingUid);
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to removeActiveConfigsChangedOperation with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void setBroadcastSubscriber(long configId, long subscriberId,
PendingIntent pendingIntent, String packageName) {
//no-op
if (DEBUG) {
Slog.d(TAG, "setBroadcastSubscriber");
enforceDumpAndUsageStatsPermission(packageName);
int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
PendingIntentRef pir = new PendingIntentRef(pendingIntent, mContext);
ConfigKey key = new ConfigKey(callingUid, configId);
// We add the PIR to a map so we can reregister if statsd is unavailable.
synchronized (mLock) {
ArrayMap<Long, PendingIntentRef> innerMap = mBroadcastSubscriberPirMap
.getOrDefault(key, new ArrayMap<>());
innerMap.put(subscriberId, pir);
mBroadcastSubscriberPirMap.put(key, innerMap);
}
try {
IStatsd statsd = getStatsdNonblocking();
if (statsd != null) {
statsd.setBroadcastSubscriber(
configId, subscriberId, pir, callingUid);
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setBroadcastSubscriber with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void unsetBroadcastSubscriber(long configId, long subscriberId, String packageName) {
enforceDumpAndUsageStatsPermission(packageName);
int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
ConfigKey key = new ConfigKey(callingUid, configId);
synchronized (mLock) {
ArrayMap<Long, PendingIntentRef> innerMap = mBroadcastSubscriberPirMap
.getOrDefault(key, new ArrayMap<>());
innerMap.remove(subscriberId);
if (innerMap.isEmpty()) {
mBroadcastSubscriberPirMap.remove(key);
}
}
try {
IStatsd statsd = getStatsdNonblocking();
if (statsd != null) {
statsd.unsetBroadcastSubscriber(configId, subscriberId, callingUid);
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to unsetBroadcastSubscriber with statsd");
} finally {
Binder.restoreCallingIdentity(token);
}
}
@@ -77,37 +249,130 @@ public class StatsManagerService extends IStatsManagerService.Stub {
mStatsCompanionService = statsCompanionService;
}
void systemReady() {
if (DEBUG) {
Slog.d(TAG, "statsdReady");
private void enforceDumpAndUsageStatsPermission(String packageName) {
int callingUid = Binder.getCallingUid();
int callingPid = Binder.getCallingPid();
if (callingPid == Process.myPid()) {
return;
}
mContext.enforceCallingPermission(Manifest.permission.DUMP, null);
mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS, null);
AppOpsManager appOpsManager = (AppOpsManager) mContext
.getSystemService(Context.APP_OPS_SERVICE);
switch (appOpsManager.noteOp(USAGE_STATS_PERMISSION_OPS,
Binder.getCallingUid(), packageName, null, null)) {
case AppOpsManager.MODE_ALLOWED:
case AppOpsManager.MODE_DEFAULT:
break;
default:
throw new SecurityException(
String.format("UID %d / PID %d lacks app-op %s",
callingUid, callingPid, USAGE_STATS_PERMISSION_OPS)
);
}
setupStatsManagerService();
}
private void setupStatsManagerService() {
synchronized (sStatsdLock) {
if (sStatsd != null) {
if (DEBUG) {
Slog.e(TAG, "Trying to fetch statsd, but it was already fetched",
new IllegalStateException(
"sStatsd is not null when being fetched"));
/**
* Clients should call this if blocking until statsd to be ready is desired
*
* @return IStatsd object if statsd becomes ready within the timeout, null otherwise.
*/
private IStatsd waitForStatsd() {
synchronized (mLock) {
if (mStatsd == null) {
try {
mLock.wait(STATSD_TIMEOUT_MILLIS);
} catch (InterruptedException e) {
Slog.e(TAG, "wait for statsd interrupted");
}
return;
}
sStatsd = IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
if (sStatsd == null) {
if (DEBUG) {
Slog.d(TAG, "Failed to get stats service.");
}
return;
return mStatsd;
}
}
/**
* Clients should call this to receive a reference to statsd.
*
* @return IStatsd object if statsd is ready, null otherwise.
*/
private IStatsd getStatsdNonblocking() {
synchronized (mLock) {
return mStatsd;
}
}
/**
* Called from {@link StatsCompanionService}.
*
* Tells StatsManagerService that Statsd is ready and updates
* Statsd with the contents of our local cache.
*/
void statsdReady(IStatsd statsd) {
synchronized (mLock) {
mStatsd = statsd;
mLock.notify();
}
sayHiToStatsd(statsd);
}
/**
* Called from {@link StatsCompanionService}.
*
* Tells StatsManagerService that Statsd is no longer ready
* and we should no longer make binder calls with statsd.
*/
void statsdNotReady() {
synchronized (mLock) {
mStatsd = null;
}
}
private void sayHiToStatsd(IStatsd statsd) {
if (statsd == null) {
return;
}
// Since we do not want to make an IPC with the a lock held, we first create local deep
// copies of the data with the lock held before iterating through the maps.
ArrayMap<ConfigKey, PendingIntentRef> dataFetchCopy;
ArrayMap<Integer, PendingIntentRef> activeConfigsChangedCopy;
ArrayMap<ConfigKey, ArrayMap<Long, PendingIntentRef>> broadcastSubscriberCopy;
synchronized (mLock) {
dataFetchCopy = new ArrayMap<>(mDataFetchPirMap);
activeConfigsChangedCopy = new ArrayMap<>(mActiveConfigsPirMap);
broadcastSubscriberCopy = new ArrayMap<>();
for (Map.Entry<ConfigKey, ArrayMap<Long, PendingIntentRef>> entry
: mBroadcastSubscriberPirMap.entrySet()) {
broadcastSubscriberCopy.put(entry.getKey(), new ArrayMap<>(entry.getValue()));
}
// Assume statsd is ready since this is called form statscompanion, link to statsd.
}
for (Map.Entry<ConfigKey, PendingIntentRef> entry : dataFetchCopy.entrySet()) {
ConfigKey key = entry.getKey();
try {
sStatsd.asBinder().linkToDeath((IBinder.DeathRecipient) () -> {
sStatsd = null;
}, 0);
statsd.setDataFetchOperation(key.getConfigId(), entry.getValue(), key.getUid());
} catch (RemoteException e) {
Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
Slog.e(TAG, "Failed to setDataFetchOperation from pirMap");
}
}
for (Map.Entry<Integer, PendingIntentRef> entry
: activeConfigsChangedCopy.entrySet()) {
try {
statsd.setActiveConfigsChangedOperation(entry.getValue(), entry.getKey());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setActiveConfigsChangedOperation from pirMap");
}
}
for (Map.Entry<ConfigKey, ArrayMap<Long, PendingIntentRef>> entry
: broadcastSubscriberCopy.entrySet()) {
for (Map.Entry<Long, PendingIntentRef> subscriberEntry : entry.getValue().entrySet()) {
ConfigKey configKey = entry.getKey();
try {
statsd.setBroadcastSubscriber(configKey.getConfigId(), subscriberEntry.getKey(),
subscriberEntry.getValue(), configKey.getUid());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setBroadcastSubscriber from pirMap");
}
}
}
}

View File

@@ -170,33 +170,32 @@ StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQ
mUidMap, mPullerManager, mAnomalyAlarmMonitor, mPeriodicAlarmMonitor,
getElapsedRealtimeNs(),
[this](const ConfigKey& key) {
sp<IStatsCompanionService> sc = getStatsCompanionService();
auto receiver = mConfigManager->GetConfigReceiver(key);
if (sc == nullptr) {
VLOG("Could not find StatsCompanionService");
sp<IPendingIntentRef> receiver = mConfigManager->GetConfigReceiver(key);
if (receiver == nullptr) {
VLOG("Could not find a broadcast receiver for %s",
key.ToString().c_str());
return false;
} else if (receiver == nullptr) {
VLOG("Statscompanion could not find a broadcast receiver for %s",
key.ToString().c_str());
return false;
} else {
sc->sendDataBroadcast(receiver, mProcessor->getLastReportTimeNs(key));
} else if (receiver->sendDataBroadcast(
mProcessor->getLastReportTimeNs(key)).isOk()) {
return true;
} else {
VLOG("Failed to send a broadcast for receiver %s",
key.ToString().c_str());
return false;
}
},
[this](const int& uid, const vector<int64_t>& activeConfigs) {
auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
sp<IStatsCompanionService> sc = getStatsCompanionService();
if (sc == nullptr) {
VLOG("Could not access statsCompanion");
return false;
} else if (receiver == nullptr) {
sp<IPendingIntentRef> receiver =
mConfigManager->GetActiveConfigsChangedReceiver(uid);
if (receiver == nullptr) {
VLOG("Could not find receiver for uid %d", uid);
return false;
} else {
sc->sendActiveConfigsChangedBroadcast(receiver, activeConfigs);
} else if (receiver->sendActiveConfigsChangedBroadcast(activeConfigs).isOk()) {
VLOG("StatsService::active configs broadcast succeeded for uid %d" , uid);
return true;
} else {
VLOG("StatsService::active configs broadcast failed for uid %d" , uid);
return false;
}
});
@@ -574,18 +573,19 @@ status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
return UNKNOWN_ERROR;
}
ConfigKey key(uid, StrToInt64(name));
auto receiver = mConfigManager->GetConfigReceiver(key);
sp<IStatsCompanionService> sc = getStatsCompanionService();
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, mProcessor->getLastReportTimeNs(key));
sp<IPendingIntentRef> receiver = mConfigManager->GetConfigReceiver(key);
if (receiver == nullptr) {
VLOG("Could not find receiver for %s, %s", args[1].c_str(), args[2].c_str());
return UNKNOWN_ERROR;
} else if (receiver->sendDataBroadcast(
mProcessor->getLastReportTimeNs(key)).isOk()) {
VLOG("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(),
args[2].c_str());
} else {
VLOG("StatsService::trigger broadcast failed to %s, %s", args[1].c_str(),
args[2].c_str());
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
@@ -629,15 +629,15 @@ status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<Strin
}
}
}
auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
sp<IStatsCompanionService> sc = getStatsCompanionService();
if (sc == nullptr) {
VLOG("Could not access statsCompanion");
} else if (receiver == nullptr) {
sp<IPendingIntentRef> receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
if (receiver == nullptr) {
VLOG("Could not find receiver for uid %d", uid);
} else {
sc->sendActiveConfigsChangedBroadcast(receiver, configIds);
return UNKNOWN_ERROR;
} else if (receiver->sendActiveConfigsChangedBroadcast(configIds).isOk()) {
VLOG("StatsService::trigger active configs changed broadcast succeeded for uid %d" , uid);
} else {
VLOG("StatsService::trigger active configs changed broadcast failed for uid %d", uid);
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
@@ -1111,7 +1111,6 @@ Status StatsService::statsCompanionReady() {
mPullerManager->SetStatsCompanionService(statsCompanion);
mAnomalyAlarmMonitor->setStatsCompanionService(statsCompanion);
mPeriodicAlarmMonitor->setStatsCompanionService(statsCompanion);
SubscriberReporter::getInstance().setStatsCompanionService(statsCompanion);
return Status::ok();
}
@@ -1185,23 +1184,21 @@ bool StatsService::addConfigurationChecked(int uid, int64_t key, const vector<ui
return true;
}
Status StatsService::removeDataFetchOperation(int64_t key, const String16& packageName) {
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), key);
Status StatsService::removeDataFetchOperation(int64_t key,
const int32_t callingUid) {
ENFORCE_UID(AID_SYSTEM);
ConfigKey configKey(callingUid, key);
mConfigManager->RemoveConfigReceiver(configKey);
return Status::ok();
}
Status StatsService::setDataFetchOperation(int64_t key,
const sp<android::IBinder>& intentSender,
const String16& packageName) {
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
const sp<IPendingIntentRef>& pir,
const int32_t callingUid) {
ENFORCE_UID(AID_SYSTEM);
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), key);
mConfigManager->SetConfigReceiver(configKey, intentSender);
ConfigKey configKey(callingUid, key);
mConfigManager->SetConfigReceiver(configKey, pir);
if (StorageManager::hasConfigMetricsReport(configKey)) {
VLOG("StatsService::setDataFetchOperation marking configKey %s to dump reports on disk",
configKey.ToString().c_str());
@@ -1210,27 +1207,24 @@ Status StatsService::setDataFetchOperation(int64_t key,
return Status::ok();
}
Status StatsService::setActiveConfigsChangedOperation(const sp<android::IBinder>& intentSender,
const String16& packageName,
Status StatsService::setActiveConfigsChangedOperation(const sp<IPendingIntentRef>& pir,
const int32_t callingUid,
vector<int64_t>* output) {
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
ENFORCE_UID(AID_SYSTEM);
IPCThreadState* ipc = IPCThreadState::self();
int uid = ipc->getCallingUid();
mConfigManager->SetActiveConfigsChangedReceiver(uid, intentSender);
mConfigManager->SetActiveConfigsChangedReceiver(callingUid, pir);
if (output != nullptr) {
mProcessor->GetActiveConfigs(uid, *output);
mProcessor->GetActiveConfigs(callingUid, *output);
} else {
ALOGW("StatsService::setActiveConfigsChanged output was nullptr");
}
return Status::ok();
}
Status StatsService::removeActiveConfigsChangedOperation(const String16& packageName) {
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
Status StatsService::removeActiveConfigsChangedOperation(const int32_t callingUid) {
ENFORCE_UID(AID_SYSTEM);
IPCThreadState* ipc = IPCThreadState::self();
mConfigManager->RemoveActiveConfigsChangedReceiver(ipc->getCallingUid());
mConfigManager->RemoveActiveConfigsChangedReceiver(callingUid);
return Status::ok();
}
@@ -1246,26 +1240,24 @@ Status StatsService::removeConfiguration(int64_t key, const String16& packageNam
Status StatsService::setBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
const sp<android::IBinder>& intentSender,
const String16& packageName) {
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
const sp<IPendingIntentRef>& pir,
const int32_t callingUid) {
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::setBroadcastSubscriber called.");
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), configId);
ConfigKey configKey(callingUid, configId);
SubscriberReporter::getInstance()
.setBroadcastSubscriber(configKey, subscriberId, intentSender);
.setBroadcastSubscriber(configKey, subscriberId, pir);
return Status::ok();
}
Status StatsService::unsetBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
const String16& packageName) {
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
const int32_t callingUid) {
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::unsetBroadcastSubscriber called.");
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), configId);
ConfigKey configKey(callingUid, configId);
SubscriberReporter::getInstance()
.unsetBroadcastSubscriber(configKey, subscriberId);
return Status::ok();
@@ -1631,7 +1623,6 @@ void StatsService::binderDied(const wp <IBinder>& who) {
}
mAnomalyAlarmMonitor->setStatsCompanionService(nullptr);
mPeriodicAlarmMonitor->setStatsCompanionService(nullptr);
SubscriberReporter::getInstance().setStatsCompanionService(nullptr);
mPullerManager->SetStatsCompanionService(nullptr);
}

View File

@@ -30,6 +30,7 @@
#include <android/frameworks/stats/1.0/IStats.h>
#include <android/frameworks/stats/1.0/types.h>
#include <android/os/BnStatsd.h>
#include <android/os/IPendingIntentRef.h>
#include <android/os/IStatsCompanionService.h>
#include <android/os/IStatsd.h>
#include <binder/IResultReceiver.h>
@@ -121,26 +122,26 @@ public:
* Binder call to let clients register the data fetch operation for a configuration.
*/
virtual Status setDataFetchOperation(int64_t key,
const sp<android::IBinder>& intentSender,
const String16& packageName) override;
const sp<IPendingIntentRef>& pir,
const int32_t callingUid) override;
/**
* Binder call to remove the data fetch operation for the specified config key.
*/
virtual Status removeDataFetchOperation(int64_t key,
const String16& packageName) override;
const int32_t callingUid) override;
/**
* Binder call to let clients register the active configs changed operation.
*/
virtual Status setActiveConfigsChangedOperation(const sp<android::IBinder>& intentSender,
const String16& packageName,
virtual Status setActiveConfigsChangedOperation(const sp<IPendingIntentRef>& pir,
const int32_t callingUid,
vector<int64_t>* output) override;
/**
* Binder call to remove the active configs changed operation for the specified package..
*/
virtual Status removeActiveConfigsChangedOperation(const String16& packageName) override;
virtual Status removeActiveConfigsChangedOperation(const int32_t callingUid) override;
/**
* Binder call to allow clients to remove the specified configuration.
*/
@@ -148,20 +149,19 @@ public:
const String16& packageName) override;
/**
* Binder call to associate the given config's subscriberId with the given intentSender.
* intentSender must be convertible into an IntentSender (in Java) using IntentSender(IBinder).
* Binder call to associate the given config's subscriberId with the given pendingIntentRef.
*/
virtual Status setBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
const sp<android::IBinder>& intentSender,
const String16& packageName) override;
const sp<IPendingIntentRef>& pir,
const int32_t callingUid) override;
/**
* Binder call to unassociate the given config's subscriberId with any intentSender.
* Binder call to unassociate the given config's subscriberId with any pendingIntentRef.
*/
virtual Status unsetBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
const String16& packageName) override;
const int32_t callingUid) override;
/** Inform statsCompanion that statsd is ready. */
virtual void sayHiToStatsCompanion();

View File

@@ -46,6 +46,41 @@ using std::vector;
using android::base::StringPrintf;
using std::unique_ptr;
class ConfigReceiverDeathRecipient : public android::IBinder::DeathRecipient {
public:
ConfigReceiverDeathRecipient(sp<ConfigManager> configManager, const ConfigKey& configKey):
mConfigManager(configManager),
mConfigKey(configKey) {}
~ConfigReceiverDeathRecipient() override = default;
private:
sp<ConfigManager> mConfigManager;
ConfigKey mConfigKey;
void binderDied(const android::wp<android::IBinder>& who) override {
if (IInterface::asBinder(mConfigManager->GetConfigReceiver(mConfigKey)) == who.promote()) {
mConfigManager->RemoveConfigReceiver(mConfigKey);
}
}
};
class ActiveConfigChangedReceiverDeathRecipient : public android::IBinder::DeathRecipient {
public:
ActiveConfigChangedReceiverDeathRecipient(sp<ConfigManager> configManager, const int uid):
mConfigManager(configManager),
mUid(uid) {}
~ActiveConfigChangedReceiverDeathRecipient() override = default;
private:
sp<ConfigManager> mConfigManager;
int mUid;
void binderDied(const android::wp<android::IBinder>& who) override {
if (IInterface::asBinder(mConfigManager->GetActiveConfigsChangedReceiver(mUid))
== who.promote()) {
mConfigManager->RemoveActiveConfigsChangedReceiver(mUid);
}
}
};
ConfigManager::ConfigManager() {
}
@@ -118,9 +153,11 @@ void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& confi
}
}
void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) {
void ConfigManager::SetConfigReceiver(const ConfigKey& key,
const sp<IPendingIntentRef>& pir) {
lock_guard<mutex> lock(mMutex);
mConfigReceivers[key] = intentSender;
mConfigReceivers[key] = pir;
IInterface::asBinder(pir)->linkToDeath(new ConfigReceiverDeathRecipient(this, key));
}
void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
@@ -129,9 +166,11 @@ void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
}
void ConfigManager::SetActiveConfigsChangedReceiver(const int uid,
const sp<IBinder>& intentSender) {
const sp<IPendingIntentRef>& pir) {
lock_guard<mutex> lock(mMutex);
mActiveConfigsChangedReceivers[uid] = intentSender;
mActiveConfigsChangedReceivers[uid] = pir;
IInterface::asBinder(pir)->linkToDeath(
new ActiveConfigChangedReceiverDeathRecipient(this, uid));
}
void ConfigManager::RemoveActiveConfigsChangedReceiver(const int uid) {
@@ -266,7 +305,7 @@ vector<ConfigKey> ConfigManager::GetAllConfigKeys() const {
return ret;
}
const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
const sp<IPendingIntentRef> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
lock_guard<mutex> lock(mMutex);
auto it = mConfigReceivers.find(key);
@@ -277,7 +316,7 @@ const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key
}
}
const sp<android::IBinder> ConfigManager::GetActiveConfigsChangedReceiver(const int uid) const {
const sp<IPendingIntentRef> ConfigManager::GetActiveConfigsChangedReceiver(const int uid) const {
lock_guard<mutex> lock(mMutex);
auto it = mActiveConfigsChangedReceivers.find(uid);

View File

@@ -16,10 +16,10 @@
#pragma once
#include "binder/IBinder.h"
#include "config/ConfigKey.h"
#include "config/ConfigListener.h"
#include <android/os/IPendingIntentRef.h>
#include <map>
#include <mutex>
#include <set>
@@ -64,12 +64,12 @@ public:
/**
* Sets the broadcast receiver for a configuration key.
*/
void SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender);
void SetConfigReceiver(const ConfigKey& key, const sp<IPendingIntentRef>& pir);
/**
* Returns the package name and class name representing the broadcast receiver for this config.
*/
const sp<android::IBinder> GetConfigReceiver(const ConfigKey& key) const;
const sp<IPendingIntentRef> GetConfigReceiver(const ConfigKey& key) const;
/**
* Returns all config keys registered.
@@ -85,13 +85,13 @@ public:
* Sets the broadcast receiver that is notified whenever the list of active configs
* changes for this uid.
*/
void SetActiveConfigsChangedReceiver(const int uid, const sp<IBinder>& intentSender);
void SetActiveConfigsChangedReceiver(const int uid, const sp<IPendingIntentRef>& pir);
/**
* Returns the broadcast receiver for active configs changed for this uid.
*/
const sp<IBinder> GetActiveConfigsChangedReceiver(const int uid) const;
const sp<IPendingIntentRef> GetActiveConfigsChangedReceiver(const int uid) const;
/**
* Erase any active configs changed broadcast receiver associated with this uid.
@@ -141,16 +141,15 @@ private:
std::map<int, std::set<ConfigKey>> mConfigs;
/**
* Each config key can be subscribed by up to one receiver, specified as IBinder from
* PendingIntent.
* Each config key can be subscribed by up to one receiver, specified as IPendingIntentRef.
*/
std::map<ConfigKey, sp<android::IBinder>> mConfigReceivers;
std::map<ConfigKey, sp<IPendingIntentRef>> mConfigReceivers;
/**
* Each uid can be subscribed by up to one receiver to notify that the list of active configs
* for this uid has changed. The receiver is specified as IBinder from PendingIntent.
* for this uid has changed. The receiver is specified as IPendingIntentRef.
*/
std::map<int, sp<android::IBinder>> mActiveConfigsChangedReceivers;
std::map<int, sp<IPendingIntentRef>> mActiveConfigsChangedReceivers;
/**
* The ConfigListeners that will be told about changes.

View File

@@ -19,7 +19,6 @@
#include "SubscriberReporter.h"
using android::IBinder;
using std::lock_guard;
using std::unordered_map;
@@ -29,12 +28,32 @@ namespace statsd {
using std::vector;
class BroadcastSubscriberDeathRecipient : public android::IBinder::DeathRecipient {
public:
BroadcastSubscriberDeathRecipient(const ConfigKey& configKey, int64_t subscriberId):
mConfigKey(configKey),
mSubscriberId(subscriberId) {}
~BroadcastSubscriberDeathRecipient() override = default;
private:
ConfigKey mConfigKey;
int64_t mSubscriberId;
void binderDied(const android::wp<android::IBinder>& who) override {
if (IInterface::asBinder(SubscriberReporter::getInstance().getBroadcastSubscriber(
mConfigKey, mSubscriberId)) == who.promote()) {
SubscriberReporter::getInstance().unsetBroadcastSubscriber(mConfigKey, mSubscriberId);
}
}
};
void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId,
const sp<IBinder>& intentSender) {
const sp<IPendingIntentRef>& pir) {
VLOG("SubscriberReporter::setBroadcastSubscriber called.");
lock_guard<std::mutex> lock(mLock);
mIntentMap[configKey][subscriberId] = intentSender;
mIntentMap[configKey][subscriberId] = pir;
IInterface::asBinder(pir)->linkToDeath(
new BroadcastSubscriberDeathRecipient(configKey, subscriberId));
}
void SubscriberReporter::unsetBroadcastSubscriber(const ConfigKey& configKey,
@@ -97,18 +116,13 @@ void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey);
}
void SubscriberReporter::sendBroadcastLocked(const sp<IBinder>& intentSender,
void SubscriberReporter::sendBroadcastLocked(const sp<IPendingIntentRef>& pir,
const ConfigKey& configKey,
const Subscription& subscription,
const vector<String16>& cookies,
const MetricDimensionKey& dimKey) const {
VLOG("SubscriberReporter::sendBroadcastLocked called.");
if (mStatsCompanionService == nullptr) {
ALOGW("Failed to send subscriber broadcast: could not access StatsCompanionService.");
return;
}
mStatsCompanionService->sendSubscriberBroadcast(
intentSender,
pir->sendSubscriberBroadcast(
configKey.GetUid(),
configKey.GetId(),
subscription.id(),
@@ -117,6 +131,20 @@ void SubscriberReporter::sendBroadcastLocked(const sp<IBinder>& intentSender,
getStatsDimensionsValue(dimKey.getDimensionKeyInWhat()));
}
sp<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId) {
lock_guard<std::mutex> lock(mLock);
auto subscriberMapIt = mIntentMap.find(configKey);
if (subscriberMapIt == mIntentMap.end()) {
return nullptr;
}
auto pirMapIt = subscriberMapIt->second.find(subscriberId);
if (pirMapIt == subscriberMapIt->second.end()) {
return nullptr;
}
return pirMapIt->second;
}
void getStatsDimensionsValueHelper(const vector<FieldValue>& dims, size_t* index, int depth,
int prefix, vector<StatsDimensionsValue>* output) {
size_t count = dims.size();

View File

@@ -16,6 +16,7 @@
#pragma once
#include <android/os/IPendingIntentRef.h>
#include <android/os/IStatsCompanionService.h>
#include <utils/RefBase.h>
@@ -46,24 +47,12 @@ public:
SubscriberReporter(SubscriberReporter const&) = delete;
void operator=(SubscriberReporter const&) = delete;
/**
* Tells SubscriberReporter what IStatsCompanionService to use.
* May be nullptr, but SubscriberReporter will not send broadcasts for any calls
* to alertBroadcastSubscriber that occur while nullptr.
*/
void setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
std::lock_guard<std::mutex> lock(mLock);
sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
mStatsCompanionService = statsCompanionService;
}
/**
* Stores the given intentSender, associating it with the given (configKey, subscriberId) pair.
* intentSender must be convertible into an IntentSender (in Java) using IntentSender(IBinder).
*/
void setBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId,
const sp<android::IBinder>& intentSender);
const sp<IPendingIntentRef>& pir);
/**
* Erases any intentSender information from the given (configKey, subscriberId) pair.
@@ -82,6 +71,8 @@ public:
const Subscription& subscription,
const MetricDimensionKey& dimKey) const;
sp<IPendingIntentRef> getBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId);
static StatsDimensionsValue getStatsDimensionsValue(const HashableDimensionKey& dim);
private:
@@ -92,15 +83,15 @@ private:
/** Binder interface for communicating with StatsCompanionService. */
sp<IStatsCompanionService> mStatsCompanionService = nullptr;
/** Maps <ConfigKey, SubscriberId> -> IBinder (which represents an IIntentSender). */
/** Maps <ConfigKey, SubscriberId> -> IPendingIntentRef (which represents a PendingIntent). */
std::unordered_map<ConfigKey,
std::unordered_map<int64_t, sp<android::IBinder>>> mIntentMap;
std::unordered_map<int64_t, sp<IPendingIntentRef>>> mIntentMap;
/**
* Sends a broadcast via the given intentSender (using mStatsCompanionService), along
* with the information in the other parameters.
*/
void sendBroadcastLocked(const sp<android::IBinder>& intentSender,
void sendBroadcastLocked(const sp<IPendingIntentRef>& pir,
const ConfigKey& configKey,
const Subscription& subscription,
const std::vector<String16>& cookies,

View File

@@ -255,18 +255,17 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
IStatsd service = getIStatsdLocked();
IStatsManagerService service = getIStatsManagerServiceLocked();
if (pendingIntent != null) {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
service.setBroadcastSubscriber(configKey, subscriberId, intentSender,
service.setBroadcastSubscriber(configKey, subscriberId, pendingIntent,
mContext.getOpPackageName());
} else {
service.unsetBroadcastSubscriber(configKey, subscriberId,
mContext.getOpPackageName());
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when adding broadcast subscriber", e);
Slog.e(TAG, "Failed to connect to statsmanager when adding broadcast subscriber",
e);
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -309,18 +308,16 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
IStatsd service = getIStatsdLocked();
IStatsManagerService service = getIStatsManagerServiceLocked();
if (pendingIntent == null) {
service.removeDataFetchOperation(configKey, mContext.getOpPackageName());
} else {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
service.setDataFetchOperation(configKey, intentSender,
service.setDataFetchOperation(configKey, pendingIntent,
mContext.getOpPackageName());
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to connect to statsd when registering data listener.");
Slog.e(TAG, "Failed to connect to statsmanager when registering data listener.");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);
@@ -347,20 +344,18 @@ public final class StatsManager {
throws StatsUnavailableException {
synchronized (sLock) {
try {
IStatsd service = getIStatsdLocked();
IStatsManagerService service = getIStatsManagerServiceLocked();
if (pendingIntent == null) {
service.removeActiveConfigsChangedOperation(mContext.getOpPackageName());
return new long[0];
} else {
// Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
IBinder intentSender = pendingIntent.getTarget().asBinder();
return service.setActiveConfigsChangedOperation(intentSender,
return service.setActiveConfigsChangedOperation(pendingIntent,
mContext.getOpPackageName());
}
} catch (RemoteException e) {
Slog.e(TAG,
"Failed to connect to statsd when registering active configs listener.");
Slog.e(TAG, "Failed to connect to statsmanager "
+ "when registering active configs listener.");
throw new StatsUnavailableException("could not connect", e);
} catch (SecurityException e) {
throw new StatsUnavailableException(e.getMessage(), e);