189 lines
7.6 KiB
Java
189 lines
7.6 KiB
Java
/*
|
|
* 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 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.os.StatsDimensionsValueParcel;
|
|
import android.util.Log;
|
|
|
|
import com.android.server.SystemService;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public class StatsCompanion {
|
|
private static final String TAG = "StatsCompanion";
|
|
private static final boolean DEBUG = false;
|
|
|
|
private static final int AID_STATSD = 1066;
|
|
|
|
private static final String STATS_COMPANION_SERVICE = "statscompanion";
|
|
private static final String STATS_MANAGER_SERVICE = "statsmanager";
|
|
|
|
static void enforceStatsdCallingUid() {
|
|
if (Binder.getCallingPid() == Process.myPid()) {
|
|
return;
|
|
}
|
|
if (Binder.getCallingUid() != AID_STATSD) {
|
|
throw new SecurityException("Not allowed to access StatsCompanion");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lifecycle class for both {@link StatsCompanionService} and {@link StatsManagerService}.
|
|
*/
|
|
public static final class Lifecycle extends SystemService {
|
|
private StatsCompanionService mStatsCompanionService;
|
|
private StatsManagerService mStatsManagerService;
|
|
|
|
public Lifecycle(Context context) {
|
|
super(context);
|
|
}
|
|
|
|
@Override
|
|
public void onStart() {
|
|
mStatsCompanionService = new StatsCompanionService(getContext());
|
|
mStatsManagerService = new StatsManagerService(getContext());
|
|
mStatsCompanionService.setStatsManagerService(mStatsManagerService);
|
|
mStatsManagerService.setStatsCompanionService(mStatsCompanionService);
|
|
|
|
try {
|
|
publishBinderService(STATS_COMPANION_SERVICE, mStatsCompanionService);
|
|
if (DEBUG) Log.d(TAG, "Published " + STATS_COMPANION_SERVICE);
|
|
publishBinderService(STATS_MANAGER_SERVICE, mStatsManagerService);
|
|
if (DEBUG) Log.d(TAG, "Published " + STATS_MANAGER_SERVICE);
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Failed to publishBinderService", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onBootPhase(int phase) {
|
|
super.onBootPhase(phase);
|
|
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
|
|
mStatsCompanionService.systemReady();
|
|
}
|
|
if (phase == PHASE_BOOT_COMPLETED) {
|
|
mStatsCompanionService.bootCompleted();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
enforceStatsdCallingUid();
|
|
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) {
|
|
Log.w(TAG, "Unable to send PendingIntent");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void sendActiveConfigsChangedBroadcast(long[] configIds) {
|
|
enforceStatsdCallingUid();
|
|
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) {
|
|
Log.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
|
|
}
|
|
} catch (PendingIntent.CanceledException e) {
|
|
Log.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,
|
|
StatsDimensionsValueParcel dimensionsValueParcel) {
|
|
enforceStatsdCallingUid();
|
|
StatsDimensionsValue dimensionsValue = new StatsDimensionsValue(dimensionsValueParcel);
|
|
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) {
|
|
Log.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) {
|
|
Log.w(TAG,
|
|
"Unable to send using PendingIntent from uid " + configUid
|
|
+ "; presumably it had been cancelled.");
|
|
}
|
|
}
|
|
}
|
|
}
|