Jeffrey Huang | 8c1ae5a | 2019-12-12 10:56:24 -0800 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.server.stats; |
| 18 | |
Jeffrey Huang | ad21374 | 2019-12-16 13:50:06 -0800 | [diff] [blame] | 19 | import android.app.PendingIntent; |
Jeffrey Huang | 47537a1 | 2020-01-06 15:35:34 -0800 | [diff] [blame] | 20 | import android.app.StatsManager; |
Jeffrey Huang | 8c1ae5a | 2019-12-12 10:56:24 -0800 | [diff] [blame] | 21 | import android.content.Context; |
Jeffrey Huang | ad21374 | 2019-12-16 13:50:06 -0800 | [diff] [blame] | 22 | import android.content.Intent; |
| 23 | import android.os.Binder; |
| 24 | import android.os.IPendingIntentRef; |
| 25 | import android.os.Process; |
| 26 | import android.os.StatsDimensionsValue; |
Jeffrey Huang | 8c1ae5a | 2019-12-12 10:56:24 -0800 | [diff] [blame] | 27 | import android.util.Slog; |
| 28 | |
| 29 | import com.android.server.SystemService; |
| 30 | |
Jeffrey Huang | 4f2e6bd | 2020-01-06 16:24:45 -0800 | [diff] [blame] | 31 | import java.util.ArrayList; |
Jeffrey Huang | 47537a1 | 2020-01-06 15:35:34 -0800 | [diff] [blame] | 32 | import java.util.Arrays; |
| 33 | |
Jeffrey Huang | 8c1ae5a | 2019-12-12 10:56:24 -0800 | [diff] [blame] | 34 | /** |
| 35 | * @hide |
| 36 | */ |
| 37 | public class StatsCompanion { |
| 38 | private static final String TAG = "StatsCompanion"; |
| 39 | private static final boolean DEBUG = false; |
| 40 | |
Jeffrey Huang | ad21374 | 2019-12-16 13:50:06 -0800 | [diff] [blame] | 41 | 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 Huang | 8c1ae5a | 2019-12-12 10:56:24 -0800 | [diff] [blame] | 48 | /** |
| 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 Huang | 8c1ae5a | 2019-12-12 10:56:24 -0800 | [diff] [blame] | 83 | } |
| 84 | } |
| 85 | } |
Jeffrey Huang | ad21374 | 2019-12-16 13:50:06 -0800 | [diff] [blame] | 86 | |
| 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 Huang | 47537a1 | 2020-01-06 15:35:34 -0800 | [diff] [blame] | 104 | private static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1; |
Jeffrey Huang | 4f2e6bd | 2020-01-06 16:24:45 -0800 | [diff] [blame] | 105 | private static final int CODE_SUBSCRIBER_BROADCAST = 1; |
Jeffrey Huang | ad21374 | 2019-12-16 13:50:06 -0800 | [diff] [blame] | 106 | |
| 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 Huang | 47537a1 | 2020-01-06 15:35:34 -0800 | [diff] [blame] | 129 | 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 Huang | ad21374 | 2019-12-16 13:50:06 -0800 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | @Override |
| 143 | public void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId, |
| 144 | long subscriptionRuleId, String[] cookies, StatsDimensionsValue dimensionsValue) { |
Jeffrey Huang | 4f2e6bd | 2020-01-06 16:24:45 -0800 | [diff] [blame] | 145 | 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 Huang | ad21374 | 2019-12-16 13:50:06 -0800 | [diff] [blame] | 175 | } |
| 176 | } |
Jeffrey Huang | 8c1ae5a | 2019-12-12 10:56:24 -0800 | [diff] [blame] | 177 | } |