blob: c50ff356f9352e87a793de90ed6d11b73f29bb21 [file] [log] [blame]
atroste36b1a12019-08-28 15:40:37 +01001/*
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.internal.compat;
18
atrost6624ffa2019-09-20 16:30:07 +010019import android.util.Log;
20import android.util.Slog;
atroste36b1a12019-08-28 15:40:37 +010021
atrost6624ffa2019-09-20 16:30:07 +010022import com.android.internal.annotations.GuardedBy;
atrost46333da2019-10-10 14:24:21 +010023import com.android.internal.annotations.VisibleForTesting;
Muhammad Qureshi73107042020-01-28 10:31:03 -080024import com.android.internal.util.FrameworkStatsLog;
atrost6624ffa2019-09-20 16:30:07 +010025
atrost893f84d2019-09-30 11:29:44 +010026import java.util.HashMap;
atrost6624ffa2019-09-20 16:30:07 +010027import java.util.HashSet;
atrost893f84d2019-09-30 11:29:44 +010028import java.util.Map;
atrost6624ffa2019-09-20 16:30:07 +010029import java.util.Objects;
30import java.util.Set;
31
atroste36b1a12019-08-28 15:40:37 +010032/**
33 * A helper class to report changes to stats log.
34 *
35 * @hide
36 */
37public final class ChangeReporter {
atrost6624ffa2019-09-20 16:30:07 +010038 private static final String TAG = "CompatibilityChangeReporter";
39 private int mSource;
40
atrost46333da2019-10-10 14:24:21 +010041 private static final class ChangeReport {
atrost6624ffa2019-09-20 16:30:07 +010042 long mChangeId;
43 int mState;
44
atrost893f84d2019-09-30 11:29:44 +010045 ChangeReport(long changeId, int state) {
atrost6624ffa2019-09-20 16:30:07 +010046 mChangeId = changeId;
47 mState = state;
48 }
49
50 @Override
51 public boolean equals(Object o) {
52 if (this == o) return true;
53 if (o == null || getClass() != o.getClass()) return false;
54 ChangeReport that = (ChangeReport) o;
atrost893f84d2019-09-30 11:29:44 +010055 return mChangeId == that.mChangeId
atrost6624ffa2019-09-20 16:30:07 +010056 && mState == that.mState;
57 }
58
59 @Override
60 public int hashCode() {
atrost893f84d2019-09-30 11:29:44 +010061 return Objects.hash(mChangeId, mState);
atrost6624ffa2019-09-20 16:30:07 +010062 }
63 }
64
atrost893f84d2019-09-30 11:29:44 +010065 // Maps uid to a set of ChangeReports (that were reported for that uid).
atrost6624ffa2019-09-20 16:30:07 +010066 @GuardedBy("mReportedChanges")
atrost893f84d2019-09-30 11:29:44 +010067 private final Map<Integer, Set<ChangeReport>> mReportedChanges;
atrost6624ffa2019-09-20 16:30:07 +010068
atrost46333da2019-10-10 14:24:21 +010069 // When true will of every time to debug (logcat).
70 private boolean mDebugLogAll;
71
atrost6624ffa2019-09-20 16:30:07 +010072 public ChangeReporter(int source) {
73 mSource = source;
atrost893f84d2019-09-30 11:29:44 +010074 mReportedChanges = new HashMap<>();
atrost46333da2019-10-10 14:24:21 +010075 mDebugLogAll = false;
atrost6624ffa2019-09-20 16:30:07 +010076 }
77
78 /**
atrost893f84d2019-09-30 11:29:44 +010079 * Report the change to stats log and to the debug log if the change was not previously
80 * logged already.
atrost6624ffa2019-09-20 16:30:07 +010081 *
82 * @param uid affected by the change
83 * @param changeId the reported change id
84 * @param state of the reported change - enabled/disabled/only logged
85 */
86 public void reportChange(int uid, long changeId, int state) {
atrost46333da2019-10-10 14:24:21 +010087 if (shouldWriteToStatsLog(uid, changeId, state)) {
Muhammad Qureshi73107042020-01-28 10:31:03 -080088 FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid,
89 changeId, state, mSource);
atrost46333da2019-10-10 14:24:21 +010090 }
91 if (shouldWriteToDebug(uid, changeId, state)) {
92 debugLog(uid, changeId, state);
93 }
94 markAsReported(uid, new ChangeReport(changeId, state));
95 }
96
97 /**
98 * Start logging all the time to logcat.
99 */
100 public void startDebugLogAll() {
101 mDebugLogAll = true;
102 }
103
104 /**
105 * Stop logging all the time to logcat.
106 */
107 public void stopDebugLogAll() {
108 mDebugLogAll = false;
109 }
110
111
112 /**
113 * Returns whether the next report should be logged to statsLog.
114 *
115 * @param uid affected by the change
116 * @param changeId the reported change id
117 * @param state of the reported change - enabled/disabled/only logged
118 * @return true if the report should be logged
119 */
120 @VisibleForTesting
121 public boolean shouldWriteToStatsLog(int uid, long changeId, int state) {
122 return !isAlreadyReported(uid, new ChangeReport(changeId, state));
123 }
124
125 /**
126 * Returns whether the next report should be logged to logcat.
127 *
128 * @param uid affected by the change
129 * @param changeId the reported change id
130 * @param state of the reported change - enabled/disabled/only logged
131 * @return true if the report should be logged
132 */
133 @VisibleForTesting
134 public boolean shouldWriteToDebug(int uid, long changeId, int state) {
135 return mDebugLogAll || !isAlreadyReported(uid, new ChangeReport(changeId, state));
136 }
137
138 private boolean isAlreadyReported(int uid, ChangeReport report) {
139 synchronized (mReportedChanges) {
140 Set<ChangeReport> reportedChangesForUid = mReportedChanges.get(uid);
141 if (reportedChangesForUid == null) {
142 return false;
143 } else {
144 return reportedChangesForUid.contains(report);
145 }
146 }
147 }
148
149 private void markAsReported(int uid, ChangeReport report) {
atrost6624ffa2019-09-20 16:30:07 +0100150 synchronized (mReportedChanges) {
atrost893f84d2019-09-30 11:29:44 +0100151 Set<ChangeReport> reportedChangesForUid = mReportedChanges.get(uid);
152 if (reportedChangesForUid == null) {
153 mReportedChanges.put(uid, new HashSet<ChangeReport>());
154 reportedChangesForUid = mReportedChanges.get(uid);
155 }
atrost46333da2019-10-10 14:24:21 +0100156 reportedChangesForUid.add(report);
atrost893f84d2019-09-30 11:29:44 +0100157 }
158 }
159
160 /**
161 * Clears the saved information about a given uid. Requests to report uid again will be reported
162 * regardless to the past reports.
163 *
164 * <p> Only intended to be called from PlatformCompat.
165 *
166 * @param uid to reset
167 */
168 public void resetReportedChanges(int uid) {
169 synchronized (mReportedChanges) {
170 mReportedChanges.remove(uid);
atrost6624ffa2019-09-20 16:30:07 +0100171 }
172 }
173
174 private void debugLog(int uid, long changeId, int state) {
atrost6624ffa2019-09-20 16:30:07 +0100175 String message = String.format("Compat change id reported: %d; UID %d; state: %s", changeId,
176 uid, stateToString(state));
Muhammad Qureshi73107042020-01-28 10:31:03 -0800177 if (mSource == FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER) {
atrost6624ffa2019-09-20 16:30:07 +0100178 Slog.d(TAG, message);
179 } else {
180 Log.d(TAG, message);
181 }
182
183 }
atroste36b1a12019-08-28 15:40:37 +0100184
185 /**
Muhammad Qureshi73107042020-01-28 10:31:03 -0800186 * Transforms FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE enum to a string.
atroste36b1a12019-08-28 15:40:37 +0100187 *
188 * @param state to transform
189 * @return a string representing the state
190 */
191 private static String stateToString(int state) {
192 switch (state) {
Muhammad Qureshi73107042020-01-28 10:31:03 -0800193 case FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED:
atroste36b1a12019-08-28 15:40:37 +0100194 return "LOGGED";
Muhammad Qureshi73107042020-01-28 10:31:03 -0800195 case FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED:
atroste36b1a12019-08-28 15:40:37 +0100196 return "ENABLED";
Muhammad Qureshi73107042020-01-28 10:31:03 -0800197 case FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED:
atroste36b1a12019-08-28 15:40:37 +0100198 return "DISABLED";
199 default:
200 return "UNKNOWN";
201 }
202 }
atroste36b1a12019-08-28 15:40:37 +0100203}