blob: 4383b503bfe77c2786db31cbf190b405d5a09d48 [file] [log] [blame]
Jeffrey Huang8c1ae5a2019-12-12 10:56:24 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.stats;
18
Jeffrey Huangad213742019-12-16 13:50:06 -080019import android.app.PendingIntent;
Jeffrey Huang47537a12020-01-06 15:35:34 -080020import android.app.StatsManager;
Jeffrey Huang8c1ae5a2019-12-12 10:56:24 -080021import android.content.Context;
Jeffrey Huangad213742019-12-16 13:50:06 -080022import android.content.Intent;
23import android.os.Binder;
24import android.os.IPendingIntentRef;
25import android.os.Process;
26import android.os.StatsDimensionsValue;
Jeffrey Huang8c1ae5a2019-12-12 10:56:24 -080027import android.util.Slog;
28
29import com.android.server.SystemService;
30
Jeffrey Huang4f2e6bd2020-01-06 16:24:45 -080031import java.util.ArrayList;
Jeffrey Huang47537a12020-01-06 15:35:34 -080032import java.util.Arrays;
33
Jeffrey Huang8c1ae5a2019-12-12 10:56:24 -080034/**
35 * @hide
36 */
37public class StatsCompanion {
38 private static final String TAG = "StatsCompanion";
39 private static final boolean DEBUG = false;
40
Jeffrey Huangad213742019-12-16 13:50:06 -080041 static void enforceStatsCompanionPermission(Context context) {
42 if (Binder.getCallingPid() == Process.myPid()) {
43 return;
44 }
45 context.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
46 }
47
Jeffrey Huang8c1ae5a2019-12-12 10:56:24 -080048 /**
49 * Lifecycle class for both {@link StatsCompanionService} and {@link StatsManagerService}.
50 */
51 public static final class Lifecycle extends SystemService {
52 private StatsCompanionService mStatsCompanionService;
53 private StatsManagerService mStatsManagerService;
54
55 public Lifecycle(Context context) {
56 super(context);
57 }
58
59 @Override
60 public void onStart() {
61 mStatsCompanionService = new StatsCompanionService(getContext());
62 mStatsManagerService = new StatsManagerService(getContext());
63 mStatsCompanionService.setStatsManagerService(mStatsManagerService);
64 mStatsManagerService.setStatsCompanionService(mStatsCompanionService);
65
66 try {
67 publishBinderService(Context.STATS_COMPANION_SERVICE,
68 mStatsCompanionService);
69 if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE);
70 publishBinderService(Context.STATS_MANAGER_SERVICE,
71 mStatsManagerService);
72 if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_MANAGER_SERVICE);
73 } catch (Exception e) {
74 Slog.e(TAG, "Failed to publishBinderService", e);
75 }
76 }
77
78 @Override
79 public void onBootPhase(int phase) {
80 super.onBootPhase(phase);
81 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
82 mStatsCompanionService.systemReady();
Jeffrey Huang8c1ae5a2019-12-12 10:56:24 -080083 }
84 }
85 }
Jeffrey Huangad213742019-12-16 13:50:06 -080086
87 /**
88 * Wrapper for {@link PendingIntent}. Allows Statsd to send PendingIntents.
89 */
90 public static class PendingIntentRef extends IPendingIntentRef.Stub {
91
92 private static final String TAG = "PendingIntentRef";
93
94 /**
95 * The last report time is provided with each intent registered to
96 * StatsManager#setFetchReportsOperation. This allows easy de-duping in the receiver if
97 * statsd is requesting the client to retrieve the same statsd data. The last report time
98 * corresponds to the last_report_elapsed_nanos that will provided in the current
99 * ConfigMetricsReport, and this timestamp also corresponds to the
100 * current_report_elapsed_nanos of the most recently obtained ConfigMetricsReport.
101 */
102 private static final String EXTRA_LAST_REPORT_TIME = "android.app.extra.LAST_REPORT_TIME";
103 private static final int CODE_DATA_BROADCAST = 1;
Jeffrey Huang47537a12020-01-06 15:35:34 -0800104 private static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1;
Jeffrey Huang4f2e6bd2020-01-06 16:24:45 -0800105 private static final int CODE_SUBSCRIBER_BROADCAST = 1;
Jeffrey Huangad213742019-12-16 13:50:06 -0800106
107 private final PendingIntent mPendingIntent;
108 private final Context mContext;
109
110 public PendingIntentRef(PendingIntent pendingIntent, Context context) {
111 mPendingIntent = pendingIntent;
112 mContext = context;
113 }
114
115 @Override
116 public void sendDataBroadcast(long lastReportTimeNs) {
117 enforceStatsCompanionPermission(mContext);
118 Intent intent = new Intent();
119 intent.putExtra(EXTRA_LAST_REPORT_TIME, lastReportTimeNs);
120 try {
121 mPendingIntent.send(mContext, CODE_DATA_BROADCAST, intent, null, null);
122 } catch (PendingIntent.CanceledException e) {
123 Slog.w(TAG, "Unable to send PendingIntent");
124 }
125 }
126
127 @Override
128 public void sendActiveConfigsChangedBroadcast(long[] configIds) {
Jeffrey Huang47537a12020-01-06 15:35:34 -0800129 enforceStatsCompanionPermission(mContext);
130 Intent intent = new Intent();
131 intent.putExtra(StatsManager.EXTRA_STATS_ACTIVE_CONFIG_KEYS, configIds);
132 try {
133 mPendingIntent.send(mContext, CODE_ACTIVE_CONFIGS_BROADCAST, intent, null, null);
134 if (DEBUG) {
135 Slog.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
136 }
137 } catch (PendingIntent.CanceledException e) {
138 Slog.w(TAG, "Unable to send active configs changed broadcast using PendingIntent");
139 }
Jeffrey Huangad213742019-12-16 13:50:06 -0800140 }
141
142 @Override
143 public void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
144 long subscriptionRuleId, String[] cookies, StatsDimensionsValue dimensionsValue) {
Jeffrey Huang4f2e6bd2020-01-06 16:24:45 -0800145 enforceStatsCompanionPermission(mContext);
146 Intent intent =
147 new Intent()
148 .putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
149 .putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configId)
150 .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
151 .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID,
152 subscriptionRuleId)
153 .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
154
155 ArrayList<String> cookieList = new ArrayList<>(cookies.length);
156 cookieList.addAll(Arrays.asList(cookies));
157 intent.putStringArrayListExtra(
158 StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
159
160 if (DEBUG) {
161 Slog.d(TAG,
162 String.format(
163 "Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
164 configUid, configId, subscriptionId, subscriptionRuleId,
165 Arrays.toString(cookies),
166 dimensionsValue));
167 }
168 try {
169 mPendingIntent.send(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
170 } catch (PendingIntent.CanceledException e) {
171 Slog.w(TAG,
172 "Unable to send using PendingIntent from uid " + configUid
173 + "; presumably it had been cancelled.");
174 }
Jeffrey Huangad213742019-12-16 13:50:06 -0800175 }
176 }
Jeffrey Huang8c1ae5a2019-12-12 10:56:24 -0800177}