blob: 3cdf09e967fe0a068d1ea05bfc4b6826982b03ce [file] [log] [blame]
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001/*
2 * Copyright (C) 2012 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;
18
Suprabh Shukla3017fe42018-11-08 19:00:01 -080019import static android.app.AppOpsManager.OP_PLAY_AUDIO;
Hai Zhang2b98fb32018-09-21 15:18:46 -070020import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
21import static android.app.AppOpsManager.UID_STATE_CACHED;
22import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
23import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
24import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
25import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
26import static android.app.AppOpsManager.UID_STATE_TOP;
27import static android.app.AppOpsManager._NUM_UID_STATE;
Eugene Suslae4ee2c22018-11-05 12:23:30 -080028import static android.app.AppOpsManager.modeToName;
29import static android.app.AppOpsManager.opToName;
Hai Zhang2b98fb32018-09-21 15:18:46 -070030
Philip P. Moltmanne683f192017-06-23 14:05:04 -070031import android.Manifest;
Svet Ganovad0a49b2018-10-29 10:07:08 -070032import android.annotation.NonNull;
33import android.annotation.Nullable;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070034import android.app.ActivityManager;
35import android.app.ActivityThread;
36import android.app.AppGlobals;
37import android.app.AppOpsManager;
Svet Ganovad0a49b2018-10-29 10:07:08 -070038import android.app.AppOpsManager.HistoricalOpEntry;
39import android.app.AppOpsManager.HistoricalPackageOps;
Dianne Hackbornd5254412018-05-11 18:02:58 -070040import android.app.AppOpsManagerInternal;
Svet Ganovd873ae62018-06-25 16:39:23 -070041import android.app.AppOpsManagerInternal.CheckOpsDelegate;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080042import android.content.BroadcastReceiver;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070043import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070044import android.content.Context;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080045import android.content.Intent;
46import android.content.IntentFilter;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070047import android.content.pm.ApplicationInfo;
48import android.content.pm.IPackageManager;
49import android.content.pm.PackageManager;
50import android.content.pm.PackageManagerInternal;
Svet Ganovad0a49b2018-10-29 10:07:08 -070051import android.content.pm.ParceledListSlice;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070052import android.content.pm.UserInfo;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070053import android.database.ContentObserver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070054import android.media.AudioAttributes;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070055import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070056import android.os.AsyncTask;
57import android.os.Binder;
58import android.os.Bundle;
59import android.os.Handler;
60import android.os.IBinder;
61import android.os.Process;
62import android.os.RemoteException;
63import android.os.ResultReceiver;
64import android.os.ServiceManager;
65import android.os.ShellCallback;
66import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070067import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070068import android.os.UserHandle;
69import android.os.UserManager;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -070070import android.os.storage.StorageManager;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070071import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070072import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070073import android.util.ArrayMap;
74import android.util.ArraySet;
75import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070076import android.util.KeyValueListParser;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070077import android.util.Slog;
78import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070079import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070080import android.util.SparseIntArray;
81import android.util.TimeUtils;
82import android.util.Xml;
83
Todd Kennedy556efba2018-11-15 07:43:55 -080084import com.android.internal.annotations.GuardedBy;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070085import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080086import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070087import com.android.internal.app.IAppOpsCallback;
Svet Ganovb3d2ae22018-12-17 22:06:15 -080088import com.android.internal.app.IAppOpsNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070089import com.android.internal.app.IAppOpsService;
90import com.android.internal.os.Zygote;
91import com.android.internal.util.ArrayUtils;
92import com.android.internal.util.DumpUtils;
93import com.android.internal.util.FastXmlSerializer;
94import com.android.internal.util.Preconditions;
95import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080096import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050097
Philip P. Moltmanne683f192017-06-23 14:05:04 -070098import libcore.util.EmptyArray;
99
100import org.xmlpull.v1.XmlPullParser;
101import org.xmlpull.v1.XmlPullParserException;
102import org.xmlpull.v1.XmlSerializer;
103
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800104import java.io.File;
105import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800106import java.io.FileInputStream;
107import java.io.FileNotFoundException;
108import java.io.FileOutputStream;
109import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800110import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100111import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700112import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800113import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700114import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -0700115import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700116import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800117import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800118import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800119import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700120import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800121
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800122public class AppOpsService extends IAppOpsService.Stub {
123 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800124 static final boolean DEBUG = false;
125
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700126 private static final int NO_VERSION = -1;
127 /** Increment by one every time and add the corresponding upgrade logic in
128 * {@link #upgradeLocked(int)} below. The first version was 1 */
129 private static final int CURRENT_VERSION = 1;
130
Dianne Hackborn35654b62013-01-14 17:38:02 -0800131 // Write at most every 30 minutes.
132 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800133
Svet Ganov3a95f832018-03-23 17:44:30 -0700134 // Constant meaning that any UID should be matched when dispatching callbacks
135 private static final int UID_ANY = -2;
136
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700137 // Map from process states to the uid states we track.
138 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
139 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
140 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
141 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
142 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
143 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
144 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
145 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
146 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
147 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
148 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
149 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
150 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
151 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
152 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
153 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
154 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
155 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
156 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
157 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
158 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
159 };
160
161 static final String[] UID_STATE_NAMES = new String[] {
162 "pers ", // UID_STATE_PERSISTENT
163 "top ", // UID_STATE_TOP
164 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
165 "fg ", // UID_STATE_FOREGROUND
166 "bg ", // UID_STATE_BACKGROUND
167 "cch ", // UID_STATE_CACHED
168 };
169
170 static final String[] UID_STATE_TIME_ATTRS = new String[] {
171 "tp", // UID_STATE_PERSISTENT
172 "tt", // UID_STATE_TOP
173 "tfs", // UID_STATE_FOREGROUND_SERVICE
174 "tf", // UID_STATE_FOREGROUND
175 "tb", // UID_STATE_BACKGROUND
176 "tc", // UID_STATE_CACHED
177 };
178
179 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
180 "rp", // UID_STATE_PERSISTENT
181 "rt", // UID_STATE_TOP
182 "rfs", // UID_STATE_FOREGROUND_SERVICE
183 "rf", // UID_STATE_FOREGROUND
184 "rb", // UID_STATE_BACKGROUND
185 "rc", // UID_STATE_CACHED
186 };
187
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800188 Context mContext;
189 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800190 final Handler mHandler;
191
Dianne Hackbornd5254412018-05-11 18:02:58 -0700192 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
193 = new AppOpsManagerInternalImpl();
194
Dianne Hackborn35654b62013-01-14 17:38:02 -0800195 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800196 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800197 final Runnable mWriteRunner = new Runnable() {
198 public void run() {
199 synchronized (AppOpsService.this) {
200 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800201 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800202 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
203 @Override protected Void doInBackground(Void... params) {
204 writeState();
205 return null;
206 }
207 };
208 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
209 }
210 }
211 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800212
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700213 @VisibleForTesting
214 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800215
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700216 long mLastRealtime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700217
Ruben Brunk29931bc2016-03-11 00:24:26 -0800218 /*
219 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800220 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700221 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400222
Dianne Hackbornd5254412018-05-11 18:02:58 -0700223 SparseIntArray mProfileOwners;
224
Todd Kennedy556efba2018-11-15 07:43:55 -0800225 @GuardedBy("this")
Svet Ganovd873ae62018-06-25 16:39:23 -0700226 private CheckOpsDelegate mCheckOpsDelegate;
227
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700228 /**
229 * All times are in milliseconds. These constants are kept synchronized with the system
230 * global Settings. Any access to this class or its fields should be done while
231 * holding the AppOpsService lock.
232 */
233 private final class Constants extends ContentObserver {
234 // Key names stored in the settings value.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700235 private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
236 private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
237 = "fg_service_state_settle_time";
238 private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700239
240 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700241 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700242 * @see Settings.Global#APP_OPS_CONSTANTS
Dianne Hackborne93ab412018-05-14 17:52:30 -0700243 * @see #KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700244 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700245 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700246
Dianne Hackborne93ab412018-05-14 17:52:30 -0700247 /**
248 * How long we want for a drop in uid state from foreground to settle before applying it.
249 * @see Settings.Global#APP_OPS_CONSTANTS
250 * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
251 */
252 public long FG_SERVICE_STATE_SETTLE_TIME;
253
254 /**
255 * How long we want for a drop in uid state from background to settle before applying it.
256 * @see Settings.Global#APP_OPS_CONSTANTS
257 * @see #KEY_BG_STATE_SETTLE_TIME
258 */
259 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700260
261 private final KeyValueListParser mParser = new KeyValueListParser(',');
262 private ContentResolver mResolver;
263
264 public Constants(Handler handler) {
265 super(handler);
266 updateConstants();
267 }
268
269 public void startMonitoring(ContentResolver resolver) {
270 mResolver = resolver;
271 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700272 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700273 false, this);
274 updateConstants();
275 }
276
277 @Override
278 public void onChange(boolean selfChange, Uri uri) {
279 updateConstants();
280 }
281
282 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700283 String value = mResolver != null ? Settings.Global.getString(mResolver,
284 Settings.Global.APP_OPS_CONSTANTS) : "";
285
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700286 synchronized (AppOpsService.this) {
287 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700288 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700289 } catch (IllegalArgumentException e) {
290 // Failed to parse the settings string, log this and move on
291 // with defaults.
292 Slog.e(TAG, "Bad app ops settings", e);
293 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700294 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
295 KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
296 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
297 KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
298 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
299 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700300 }
301 }
302
303 void dump(PrintWriter pw) {
304 pw.println(" Settings:");
305
Dianne Hackborne93ab412018-05-14 17:52:30 -0700306 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
307 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700308 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700309 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
310 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700311 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700312 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
313 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700314 pw.println();
315 }
316 }
317
318 private final Constants mConstants;
319
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700320 @VisibleForTesting
321 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700322 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700323
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700324 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700325 public int pendingState = UID_STATE_CACHED;
326 public long pendingStateCommitTime;
327
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700328 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700329 public ArrayMap<String, Ops> pkgOps;
330 public SparseIntArray opModes;
331
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700332 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700333 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700334 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700335
Svet Ganov2af57082015-07-30 08:44:20 -0700336 public UidState(int uid) {
337 this.uid = uid;
338 }
339
340 public void clear() {
341 pkgOps = null;
342 opModes = null;
343 }
344
345 public boolean isDefault() {
346 return (pkgOps == null || pkgOps.isEmpty())
347 && (opModes == null || opModes.size() <= 0);
348 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700349
350 int evalMode(int mode) {
351 if (mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborne93ab412018-05-14 17:52:30 -0700352 return state <= UID_STATE_LAST_NON_RESTRICTED
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700353 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
354 }
355 return mode;
356 }
357
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700358 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
359 SparseBooleanArray which) {
360 boolean curValue = which.get(op, false);
361 ArraySet<ModeCallback> callbacks = watchers.get(op);
362 if (callbacks != null) {
363 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
364 if ((callbacks.valueAt(cbi).mFlags
365 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
366 hasForegroundWatchers = true;
367 curValue = true;
368 }
369 }
370 }
371 which.put(op, curValue);
372 }
373
374 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700375 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700376 hasForegroundWatchers = false;
377 if (opModes != null) {
378 for (int i = opModes.size() - 1; i >= 0; i--) {
379 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
380 if (which == null) {
381 which = new SparseBooleanArray();
382 }
383 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
384 }
385 }
386 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700387 if (pkgOps != null) {
388 for (int i = pkgOps.size() - 1; i >= 0; i--) {
389 Ops ops = pkgOps.valueAt(i);
390 for (int j = ops.size() - 1; j >= 0; j--) {
391 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
392 if (which == null) {
393 which = new SparseBooleanArray();
394 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700395 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700396 }
397 }
398 }
399 }
400 foregroundOps = which;
401 }
Svet Ganov2af57082015-07-30 08:44:20 -0700402 }
403
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700404 final static class Ops extends SparseArray<Op> {
405 final String packageName;
406 final UidState uidState;
407 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800408
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700409 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800410 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700411 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400412 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800413 }
414 }
415
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700416 final static class Op {
417 final UidState uidState;
418 final int uid;
419 final String packageName;
420 final int op;
421 int proxyUid = -1;
422 String proxyPackageName;
423 int mode;
424 int duration;
425 long time[] = new long[_NUM_UID_STATE];
426 long rejectTime[] = new long[_NUM_UID_STATE];
427 int startNesting;
428 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800429
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700430 Op(UidState _uidState, String _packageName, int _op) {
431 uidState = _uidState;
432 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700433 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800434 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700435 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800436 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700437
438 boolean hasAnyTime() {
439 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
440 if (time[i] != 0) {
441 return true;
442 }
443 if (rejectTime[i] != 0) {
444 return true;
445 }
446 }
447 return false;
448 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700449
450 int getMode() {
451 return uidState.evalMode(mode);
452 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800453 }
454
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800455 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
456 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
457 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
458 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800459 final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800460 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800461
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700462 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800463 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700464 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700465 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700466 final int mCallingUid;
467 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800468
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700469 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700470 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800471 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700472 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700473 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700474 mCallingUid = callingUid;
475 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800476 try {
477 mCallback.asBinder().linkToDeath(this, 0);
478 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800479 /*ignored*/
Dianne Hackbornc2293022013-02-06 23:14:49 -0800480 }
481 }
482
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700483 public boolean isWatchingUid(int uid) {
484 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
485 }
486
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700487 @Override
488 public String toString() {
489 StringBuilder sb = new StringBuilder(128);
490 sb.append("ModeCallback{");
491 sb.append(Integer.toHexString(System.identityHashCode(this)));
492 sb.append(" watchinguid=");
493 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700494 sb.append(" flags=0x");
495 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700496 sb.append(" from uid=");
497 UserHandle.formatUid(sb, mCallingUid);
498 sb.append(" pid=");
499 sb.append(mCallingPid);
500 sb.append('}');
501 return sb.toString();
502 }
503
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700504 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800505 mCallback.asBinder().unlinkToDeath(this, 0);
506 }
507
508 @Override
509 public void binderDied() {
510 stopWatchingMode(mCallback);
511 }
512 }
513
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700514 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800515 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700516 final int mWatchingUid;
517 final int mCallingUid;
518 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800519
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700520 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700521 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800522 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700523 mWatchingUid = watchingUid;
524 mCallingUid = callingUid;
525 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800526 try {
527 mCallback.asBinder().linkToDeath(this, 0);
528 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800529 /*ignored*/
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800530 }
531 }
532
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700533 @Override
534 public String toString() {
535 StringBuilder sb = new StringBuilder(128);
536 sb.append("ActiveCallback{");
537 sb.append(Integer.toHexString(System.identityHashCode(this)));
538 sb.append(" watchinguid=");
539 UserHandle.formatUid(sb, mWatchingUid);
540 sb.append(" from uid=");
541 UserHandle.formatUid(sb, mCallingUid);
542 sb.append(" pid=");
543 sb.append(mCallingPid);
544 sb.append('}');
545 return sb.toString();
546 }
547
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700548 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800549 mCallback.asBinder().unlinkToDeath(this, 0);
550 }
551
552 @Override
553 public void binderDied() {
554 stopWatchingActive(mCallback);
555 }
556 }
557
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800558 final class NotedCallback implements DeathRecipient {
559 final IAppOpsNotedCallback mCallback;
560 final int mWatchingUid;
561 final int mCallingUid;
562 final int mCallingPid;
563
564 NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
565 int callingPid) {
566 mCallback = callback;
567 mWatchingUid = watchingUid;
568 mCallingUid = callingUid;
569 mCallingPid = callingPid;
570 try {
571 mCallback.asBinder().linkToDeath(this, 0);
572 } catch (RemoteException e) {
573 /*ignored*/
574 }
575 }
576
577 @Override
578 public String toString() {
579 StringBuilder sb = new StringBuilder(128);
580 sb.append("NotedCallback{");
581 sb.append(Integer.toHexString(System.identityHashCode(this)));
582 sb.append(" watchinguid=");
583 UserHandle.formatUid(sb, mWatchingUid);
584 sb.append(" from uid=");
585 UserHandle.formatUid(sb, mCallingUid);
586 sb.append(" pid=");
587 sb.append(mCallingPid);
588 sb.append('}');
589 return sb.toString();
590 }
591
592 void destroy() {
593 mCallback.asBinder().unlinkToDeath(this, 0);
594 }
595
596 @Override
597 public void binderDied() {
598 stopWatchingNoted(mCallback);
599 }
600 }
601
Svet Ganova7a0db62018-02-27 20:08:01 -0800602 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700603
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700604 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800605 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700606 final IBinder mAppToken;
607 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700608
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700609 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700610 mAppToken = appToken;
611 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800612 // Watch only for remote processes dying
613 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700614 try {
615 mAppToken.linkToDeath(this, 0);
616 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800617 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700618 }
619 }
620 }
621
622 @Override
623 public String toString() {
624 return "ClientState{" +
625 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800626 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700627 '}';
628 }
629
630 @Override
631 public void binderDied() {
632 synchronized (AppOpsService.this) {
633 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800634 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700635 }
636 mClients.remove(mAppToken);
637 }
638 }
639 }
640
Jeff Brown6f357d32014-01-15 20:40:55 -0800641 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600642 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800643 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800644 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700645 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800646 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800647 }
David Braunf5d83192013-09-16 13:43:51 -0700648
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800649 public void publish(Context context) {
650 mContext = context;
651 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -0700652 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800653 }
654
Dianne Hackborn514074f2013-02-11 10:52:46 -0800655 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700656 mConstants.startMonitoring(mContext.getContentResolver());
657
Dianne Hackborn514074f2013-02-11 10:52:46 -0800658 synchronized (this) {
659 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700660 for (int i = mUidStates.size() - 1; i >= 0; i--) {
661 UidState uidState = mUidStates.valueAt(i);
662
663 String[] packageNames = getPackagesForUid(uidState.uid);
664 if (ArrayUtils.isEmpty(packageNames)) {
665 uidState.clear();
666 mUidStates.removeAt(i);
667 changed = true;
668 continue;
669 }
670
671 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
672 if (pkgs == null) {
673 continue;
674 }
675
Dianne Hackborn514074f2013-02-11 10:52:46 -0800676 Iterator<Ops> it = pkgs.values().iterator();
677 while (it.hasNext()) {
678 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700679 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800680 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700681 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
682 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700683 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700684 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800685 }
Svet Ganov2af57082015-07-30 08:44:20 -0700686 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800687 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700688 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800689 it.remove();
690 changed = true;
691 }
692 }
Svet Ganov2af57082015-07-30 08:44:20 -0700693
694 if (uidState.isDefault()) {
695 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800696 }
697 }
698 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800699 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800700 }
701 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700702
Suprabh Shukla3017fe42018-11-08 19:00:01 -0800703 final IntentFilter packageSuspendFilter = new IntentFilter();
704 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
705 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
706 mContext.registerReceiver(new BroadcastReceiver() {
707 @Override
708 public void onReceive(Context context, Intent intent) {
709 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
710 final String[] changedPkgs = intent.getStringArrayExtra(
711 Intent.EXTRA_CHANGED_PACKAGE_LIST);
712 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
713 for (int i = 0; i < changedUids.length; i++) {
714 final int changedUid = changedUids[i];
715 final String changedPkg = changedPkgs[i];
716 // We trust packagemanager to insert matching uid and packageNames in the extras
717 mHandler.sendMessage(PooledLambda.obtainMessage(AppOpsService::notifyOpChanged,
718 AppOpsService.this, callbacks, OP_PLAY_AUDIO, changedUid, changedPkg));
719 }
720 }
721 }, packageSuspendFilter);
722
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800723 PackageManagerInternal packageManagerInternal = LocalServices.getService(
724 PackageManagerInternal.class);
725 packageManagerInternal.setExternalSourcesPolicy(
726 new PackageManagerInternal.ExternalSourcesPolicy() {
727 @Override
728 public int getPackageTrustedToInstallApps(String packageName, int uid) {
729 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
730 uid, packageName);
731 switch (appOpMode) {
732 case AppOpsManager.MODE_ALLOWED:
733 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
734 case AppOpsManager.MODE_ERRORED:
735 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
736 default:
737 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
738 }
739 }
740 });
741
Jeff Sharkey10ec9d82018-11-28 14:52:45 -0700742 if (!StorageManager.hasIsolatedStorage()) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700743 StorageManagerInternal storageManagerInternal = LocalServices.getService(
744 StorageManagerInternal.class);
745 storageManagerInternal.addExternalStoragePolicy(
746 new StorageManagerInternal.ExternalStorageMountPolicy() {
747 @Override
748 public int getMountMode(int uid, String packageName) {
749 if (Process.isIsolated(uid)) {
750 return Zygote.MOUNT_EXTERNAL_NONE;
751 }
752 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
753 packageName) != AppOpsManager.MODE_ALLOWED) {
754 return Zygote.MOUNT_EXTERNAL_NONE;
755 }
756 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
757 packageName) != AppOpsManager.MODE_ALLOWED) {
758 return Zygote.MOUNT_EXTERNAL_READ;
759 }
760 return Zygote.MOUNT_EXTERNAL_WRITE;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700761 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700762
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700763 @Override
764 public boolean hasExternalStorage(int uid, String packageName) {
765 final int mountMode = getMountMode(uid, packageName);
766 return mountMode == Zygote.MOUNT_EXTERNAL_READ
767 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
768 }
769 });
770 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800771 }
772
773 public void packageRemoved(int uid, String packageName) {
774 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700775 UidState uidState = mUidStates.get(uid);
776 if (uidState == null) {
777 return;
778 }
779
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800780 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700781
782 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800783 if (uidState.pkgOps != null) {
784 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700785 }
786
787 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800788 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700789 && getPackagesForUid(uid).length <= 0) {
790 mUidStates.remove(uid);
791 }
792
Svet Ganova7a0db62018-02-27 20:08:01 -0800793 // Finish ops other packages started on behalf of the package.
794 final int clientCount = mClients.size();
795 for (int i = 0; i < clientCount; i++) {
796 final ClientState client = mClients.valueAt(i);
797 if (client.mStartedOps == null) {
798 continue;
799 }
800 final int opCount = client.mStartedOps.size();
801 for (int j = opCount - 1; j >= 0; j--) {
802 final Op op = client.mStartedOps.get(j);
803 if (uid == op.uid && packageName.equals(op.packageName)) {
804 finishOperationLocked(op, /*finishNested*/ true);
805 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700806 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800807 scheduleOpActiveChangedIfNeededLocked(op.op,
808 uid, packageName, false);
809 }
810 }
811 }
812 }
813
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800814 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700815 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800816
817 final int opCount = ops.size();
818 for (int i = 0; i < opCount; i++) {
819 final Op op = ops.valueAt(i);
820 if (op.duration == -1) {
821 scheduleOpActiveChangedIfNeededLocked(
822 op.op, op.uid, op.packageName, false);
823 }
824 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800825 }
826 }
827 }
828
829 public void uidRemoved(int uid) {
830 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700831 if (mUidStates.indexOfKey(uid) >= 0) {
832 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800833 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800834 }
835 }
836 }
837
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700838 public void updateUidProcState(int uid, int procState) {
839 synchronized (this) {
840 final UidState uidState = getUidStateLocked(uid, true);
841 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700842 if (uidState != null && uidState.pendingState != newState) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700843 final int oldPendingState = uidState.pendingState;
844 uidState.pendingState = newState;
Dianne Hackborne93ab412018-05-14 17:52:30 -0700845 if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
846 // We are moving to a more important state, or the new state is in the
847 // foreground, then always do it immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700848 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700849 } else if (uidState.pendingStateCommitTime == 0) {
850 // We are moving to a less important state for the first time,
851 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700852 final long settleTime;
853 if (uidState.state <= UID_STATE_TOP) {
854 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
855 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
856 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
857 } else {
858 settleTime = mConstants.BG_STATE_SETTLE_TIME;
859 }
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700860 uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700861 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700862 if (uidState.startNesting != 0) {
863 // There is some actively running operation... need to find it
864 // and appropriately update its state.
865 final long now = System.currentTimeMillis();
866 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
867 final Ops ops = uidState.pkgOps.valueAt(i);
868 for (int j = ops.size() - 1; j >= 0; j--) {
869 final Op op = ops.valueAt(j);
870 if (op.startNesting > 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700871 op.time[oldPendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700872 op.time[newState] = now;
873 }
874 }
875 }
876 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700877 }
878 }
879 }
880
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800881 public void shutdown() {
882 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800883 boolean doWrite = false;
884 synchronized (this) {
885 if (mWriteScheduled) {
886 mWriteScheduled = false;
887 doWrite = true;
888 }
889 }
890 if (doWrite) {
891 writeState();
892 }
893 }
894
Dianne Hackborn72e39832013-01-18 18:36:09 -0800895 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
896 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700897 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800898 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700899 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800900 for (int j=0; j<pkgOps.size(); j++) {
901 Op curOp = pkgOps.valueAt(j);
Amith Yamasania1ce9632018-05-28 20:50:48 -0700902 final boolean running = curOp.duration == -1;
903 long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700904 ? (elapsedNow - curOp.startRealtime)
905 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800906 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700907 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700908 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800909 }
910 } else {
911 for (int j=0; j<ops.length; j++) {
912 Op curOp = pkgOps.get(ops[j]);
913 if (curOp != null) {
914 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700915 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800916 }
Amith Yamasania1ce9632018-05-28 20:50:48 -0700917 final boolean running = curOp.duration == -1;
918 final long duration = running
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700919 ? (elapsedNow - curOp.startRealtime)
920 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800921 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Amith Yamasania1ce9632018-05-28 20:50:48 -0700922 curOp.rejectTime, (int) duration, running, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700923 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800924 }
925 }
926 }
927 return resOps;
928 }
929
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700930 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -0800931 if (uidOps == null) {
932 return null;
933 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700934 ArrayList<AppOpsManager.OpEntry> resOps = null;
935 if (ops == null) {
936 resOps = new ArrayList<>();
937 for (int j=0; j<uidOps.size(); j++) {
938 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
939 0, 0, 0, -1, null));
940 }
941 } else {
942 for (int j=0; j<ops.length; j++) {
943 int index = uidOps.indexOfKey(ops[j]);
944 if (index >= 0) {
945 if (resOps == null) {
946 resOps = new ArrayList<>();
947 }
948 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
949 0, 0, 0, -1, null));
950 }
951 }
952 }
953 return resOps;
954 }
955
Dianne Hackborn35654b62013-01-14 17:38:02 -0800956 @Override
957 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
958 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
959 Binder.getCallingPid(), Binder.getCallingUid(), null);
960 ArrayList<AppOpsManager.PackageOps> res = null;
961 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700962 final int uidStateCount = mUidStates.size();
963 for (int i = 0; i < uidStateCount; i++) {
964 UidState uidState = mUidStates.valueAt(i);
965 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
966 continue;
967 }
968 ArrayMap<String, Ops> packages = uidState.pkgOps;
969 final int packageCount = packages.size();
970 for (int j = 0; j < packageCount; j++) {
971 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800972 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800973 if (resOps != null) {
974 if (res == null) {
975 res = new ArrayList<AppOpsManager.PackageOps>();
976 }
977 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700978 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800979 res.add(resPackage);
980 }
981 }
982 }
983 }
984 return res;
985 }
986
987 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800988 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
989 int[] ops) {
990 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
991 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000992 String resolvedPackageName = resolvePackageName(uid, packageName);
993 if (resolvedPackageName == null) {
994 return Collections.emptyList();
995 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800996 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700997 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
998 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800999 if (pkgOps == null) {
1000 return null;
1001 }
1002 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
1003 if (resOps == null) {
1004 return null;
1005 }
1006 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1007 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07001008 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001009 res.add(resPackage);
1010 return res;
1011 }
1012 }
1013
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001014 @Override
Svet Ganovad0a49b2018-10-29 10:07:08 -07001015 public @Nullable ParceledListSlice getAllHistoricalPackagesOps(@Nullable String[] opNames,
1016 long beginTimeMillis, long endTimeMillis) {
1017 Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
1018 "beginTimeMillis must be non negative and lesser than endTimeMillis");
1019
1020 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1021 Binder.getCallingPid(), Binder.getCallingUid(), "getAllHistoricalPackagesOps");
1022
1023 ArrayList<HistoricalPackageOps> historicalPackageOpsList = null;
1024
1025 final int uidStateCount = mUidStates.size();
1026 for (int i = 0; i < uidStateCount; i++) {
1027 final UidState uidState = mUidStates.valueAt(i);
1028 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
1029 continue;
1030 }
1031 final ArrayMap<String, Ops> packages = uidState.pkgOps;
1032 final int packageCount = packages.size();
1033 for (int j = 0; j < packageCount; j++) {
1034 final Ops pkgOps = packages.valueAt(j);
1035 final AppOpsManager.HistoricalPackageOps historicalPackageOps =
1036 createHistoricalPackageOps(uidState.uid, pkgOps, opNames,
1037 beginTimeMillis, endTimeMillis);
1038 if (historicalPackageOps != null) {
1039 if (historicalPackageOpsList == null) {
1040 historicalPackageOpsList = new ArrayList<>();
1041 }
1042 historicalPackageOpsList.add(historicalPackageOps);
1043 }
1044 }
1045 }
1046
1047 if (historicalPackageOpsList == null) {
1048 return null;
1049 }
1050
1051 return new ParceledListSlice<>(historicalPackageOpsList);
1052 }
1053
1054 private static @Nullable HistoricalPackageOps createHistoricalPackageOps(int uid,
1055 @Nullable Ops pkgOps, @Nullable String[] opNames, long beginTimeMillis,
1056 long endTimeMillis) {
1057 // TODO: Implement historical data collection
1058 if (pkgOps == null) {
1059 return null;
1060 }
1061
1062 final HistoricalPackageOps historicalPackageOps = new HistoricalPackageOps(uid,
1063 pkgOps.packageName);
1064
1065 if (opNames == null) {
1066 opNames = AppOpsManager.getOpStrs();
1067 }
1068 for (String opName : opNames) {
1069 addHistoricOpEntry(AppOpsManager.strOpToOp(opName), pkgOps, historicalPackageOps);
1070 }
1071
1072 return historicalPackageOps;
1073 }
1074
1075 @Override
1076 public @Nullable HistoricalPackageOps getHistoricalPackagesOps(int uid,
1077 @NonNull String packageName, @Nullable String[] opNames,
1078 long beginTimeMillis, long endTimeMillis) {
1079 Preconditions.checkNotNull(packageName,
1080 "packageName cannot be null");
1081 Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
1082 "beginTimeMillis must be non negative and lesser than endTimeMillis");
1083
1084 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1085 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalPackagesOps");
1086
1087 final String resolvedPackageName = resolvePackageName(uid, packageName);
1088 if (resolvedPackageName == null) {
1089 return null;
1090 }
1091
1092 // TODO: Implement historical data collection
1093 final Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
1094 false /* uidMismatchExpected */);
1095 return createHistoricalPackageOps(uid, pkgOps, opNames, beginTimeMillis, endTimeMillis);
1096 }
1097
1098 private static void addHistoricOpEntry(int opCode, @NonNull Ops ops,
1099 @NonNull HistoricalPackageOps outHistoricalPackageOps) {
1100 final Op op = ops.get(opCode);
1101 if (op == null) {
1102 return;
1103 }
1104
1105 final HistoricalOpEntry historicalOpEntry = new HistoricalOpEntry(opCode);
1106
1107 // TODO: Keep per UID state duration
1108 for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
1109 final int acceptCount;
1110 final int rejectCount;
1111 if (op.rejectTime[uidState] == 0) {
1112 acceptCount = 1;
1113 rejectCount = 0;
1114 } else {
1115 acceptCount = 0;
1116 rejectCount = 1;
1117 }
1118 historicalOpEntry.addEntry(uidState, acceptCount, rejectCount, 0);
1119 }
1120
1121 outHistoricalPackageOps.addEntry(historicalOpEntry);
1122 }
1123
1124 @Override
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001125 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
1126 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1127 Binder.getCallingPid(), Binder.getCallingUid(), null);
1128 synchronized (this) {
1129 UidState uidState = getUidStateLocked(uid, false);
1130 if (uidState == null) {
1131 return null;
1132 }
1133 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
1134 if (resOps == null) {
1135 return null;
1136 }
1137 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1138 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1139 null, uidState.uid, resOps);
1140 res.add(resPackage);
1141 return res;
1142 }
1143 }
1144
Dianne Hackborn607b4142013-08-02 18:10:10 -07001145 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001146 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001147 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
1148 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001149 if (ops != null) {
1150 ops.remove(op.op);
1151 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001152 UidState uidState = ops.uidState;
1153 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001154 if (pkgOps != null) {
1155 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001156 if (pkgOps.isEmpty()) {
1157 uidState.pkgOps = null;
1158 }
1159 if (uidState.isDefault()) {
1160 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001161 }
1162 }
1163 }
1164 }
1165 }
1166 }
1167
Dianne Hackbornd5254412018-05-11 18:02:58 -07001168 void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
1169 if (callingPid == Process.myPid()) {
1170 return;
1171 }
1172 final int callingUser = UserHandle.getUserId(callingUid);
1173 synchronized (this) {
1174 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
1175 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
1176 // Profile owners are allowed to change modes but only for apps
1177 // within their user.
1178 return;
1179 }
1180 }
1181 }
1182 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1183 Binder.getCallingPid(), Binder.getCallingUid(), null);
1184 }
1185
Dianne Hackborn72e39832013-01-18 18:36:09 -08001186 @Override
Svet Ganov2af57082015-07-30 08:44:20 -07001187 public void setUidMode(int code, int uid, int mode) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08001188 if (DEBUG) {
1189 Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
1190 + " by uid " + Binder.getCallingUid());
1191 }
1192
Dianne Hackbornd5254412018-05-11 18:02:58 -07001193 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -07001194 verifyIncomingOp(code);
1195 code = AppOpsManager.opToSwitch(code);
1196
1197 synchronized (this) {
1198 final int defaultMode = AppOpsManager.opToDefaultMode(code);
1199
1200 UidState uidState = getUidStateLocked(uid, false);
1201 if (uidState == null) {
1202 if (mode == defaultMode) {
1203 return;
1204 }
1205 uidState = new UidState(uid);
1206 uidState.opModes = new SparseIntArray();
1207 uidState.opModes.put(code, mode);
1208 mUidStates.put(uid, uidState);
1209 scheduleWriteLocked();
1210 } else if (uidState.opModes == null) {
1211 if (mode != defaultMode) {
1212 uidState.opModes = new SparseIntArray();
1213 uidState.opModes.put(code, mode);
1214 scheduleWriteLocked();
1215 }
1216 } else {
Hai Zhang2b98fb32018-09-21 15:18:46 -07001217 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
Svet Ganov2af57082015-07-30 08:44:20 -07001218 return;
1219 }
1220 if (mode == defaultMode) {
1221 uidState.opModes.delete(code);
1222 if (uidState.opModes.size() <= 0) {
1223 uidState.opModes = null;
1224 }
1225 } else {
1226 uidState.opModes.put(code, mode);
1227 }
1228 scheduleWriteLocked();
1229 }
1230 }
1231
Svetoslav215b44a2015-08-04 19:03:40 -07001232 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001233 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001234
riddle_hsu40b300f2015-11-23 13:22:03 +08001235 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001236 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001237 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001238 final int callbackCount = callbacks.size();
1239 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001240 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001241 ArraySet<String> changedPackages = new ArraySet<>();
1242 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001243 if (callbackSpecs == null) {
1244 callbackSpecs = new ArrayMap<>();
1245 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001246 callbackSpecs.put(callback, changedPackages);
1247 }
1248 }
1249
1250 for (String uidPackageName : uidPackageNames) {
1251 callbacks = mPackageModeWatchers.get(uidPackageName);
1252 if (callbacks != null) {
1253 if (callbackSpecs == null) {
1254 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07001255 }
riddle_hsu40b300f2015-11-23 13:22:03 +08001256 final int callbackCount = callbacks.size();
1257 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001258 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08001259 ArraySet<String> changedPackages = callbackSpecs.get(callback);
1260 if (changedPackages == null) {
1261 changedPackages = new ArraySet<>();
1262 callbackSpecs.put(callback, changedPackages);
1263 }
1264 changedPackages.add(uidPackageName);
1265 }
Svet Ganov2af57082015-07-30 08:44:20 -07001266 }
1267 }
1268 }
1269
1270 if (callbackSpecs == null) {
1271 return;
1272 }
1273
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001274 for (int i = 0; i < callbackSpecs.size(); i++) {
1275 final ModeCallback callback = callbackSpecs.keyAt(i);
1276 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
1277 if (reportedPackageNames == null) {
1278 mHandler.sendMessage(PooledLambda.obtainMessage(
1279 AppOpsService::notifyOpChanged,
1280 this, callback, code, uid, (String) null));
1281
1282 } else {
1283 final int reportedPackageCount = reportedPackageNames.size();
1284 for (int j = 0; j < reportedPackageCount; j++) {
1285 final String reportedPackageName = reportedPackageNames.valueAt(j);
1286 mHandler.sendMessage(PooledLambda.obtainMessage(
1287 AppOpsService::notifyOpChanged,
1288 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001289 }
1290 }
Svet Ganov2af57082015-07-30 08:44:20 -07001291 }
1292 }
1293
1294 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001295 public void setMode(int code, int uid, String packageName, int mode) {
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07001296 setMode(code, uid, packageName, mode, true, false);
1297 }
1298
1299 /**
1300 * Sets the mode for a certain op and uid.
1301 *
1302 * @param code The op code to set
1303 * @param uid The UID for which to set
1304 * @param packageName The package for which to set
1305 * @param mode The new mode to set
1306 * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
1307 * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
1308 * false})
1309 */
1310 private void setMode(int code, int uid, @NonNull String packageName, int mode,
1311 boolean verifyUid, boolean isPrivileged) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001312 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001313 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001314 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001315 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001316 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001317 UidState uidState = getUidStateLocked(uid, false);
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07001318 Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001319 if (op != null) {
1320 if (op.mode != mode) {
1321 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001322 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001323 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001324 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001325 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001326 if (cbs != null) {
1327 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001328 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001329 }
1330 repCbs.addAll(cbs);
1331 }
1332 cbs = mPackageModeWatchers.get(packageName);
1333 if (cbs != null) {
1334 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001335 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001336 }
1337 repCbs.addAll(cbs);
1338 }
David Braunf5d83192013-09-16 13:43:51 -07001339 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001340 // If going into the default mode, prune this op
1341 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -07001342 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001343 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001344 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001345 }
1346 }
1347 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001348 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001349 mHandler.sendMessage(PooledLambda.obtainMessage(
1350 AppOpsService::notifyOpChanged,
1351 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08001352 }
1353 }
1354
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001355 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
1356 int uid, String packageName) {
1357 for (int i = 0; i < callbacks.size(); i++) {
1358 final ModeCallback callback = callbacks.valueAt(i);
1359 notifyOpChanged(callback, code, uid, packageName);
1360 }
1361 }
1362
1363 private void notifyOpChanged(ModeCallback callback, int code,
1364 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001365 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001366 return;
1367 }
1368 // There are components watching for mode changes such as window manager
1369 // and location manager which are in our process. The callbacks in these
1370 // components may require permissions our remote caller does not have.
1371 final long identity = Binder.clearCallingIdentity();
1372 try {
1373 callback.mCallback.opChanged(code, uid, packageName);
1374 } catch (RemoteException e) {
1375 /* ignore */
1376 } finally {
1377 Binder.restoreCallingIdentity(identity);
1378 }
1379 }
1380
1381 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
1382 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
1383 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001384 if (cbs == null) {
1385 return callbacks;
1386 }
1387 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001388 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001389 }
Svet Ganov2af57082015-07-30 08:44:20 -07001390 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001391 final int N = cbs.size();
1392 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001393 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001394 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001395 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001396 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001397 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001398 } else {
1399 final int reportCount = reports.size();
1400 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001401 ChangeRec report = reports.get(j);
1402 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001403 duplicate = true;
1404 break;
1405 }
1406 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001407 }
Svet Ganov2af57082015-07-30 08:44:20 -07001408 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001409 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001410 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001411 }
1412 return callbacks;
1413 }
1414
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001415 static final class ChangeRec {
1416 final int op;
1417 final int uid;
1418 final String pkg;
1419
1420 ChangeRec(int _op, int _uid, String _pkg) {
1421 op = _op;
1422 uid = _uid;
1423 pkg = _pkg;
1424 }
1425 }
1426
Dianne Hackborn607b4142013-08-02 18:10:10 -07001427 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001428 public void resetAllModes(int reqUserId, String reqPackageName) {
1429 final int callingPid = Binder.getCallingPid();
1430 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001431 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1432 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001433
1434 int reqUid = -1;
1435 if (reqPackageName != null) {
1436 try {
1437 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001438 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001439 } catch (RemoteException e) {
1440 /* ignore - local call */
1441 }
1442 }
1443
Dianne Hackbornd5254412018-05-11 18:02:58 -07001444 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
1445
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001446 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001447 synchronized (this) {
1448 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001449 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1450 UidState uidState = mUidStates.valueAt(i);
1451
1452 SparseIntArray opModes = uidState.opModes;
1453 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1454 final int uidOpCount = opModes.size();
1455 for (int j = uidOpCount - 1; j >= 0; j--) {
1456 final int code = opModes.keyAt(j);
1457 if (AppOpsManager.opAllowsReset(code)) {
1458 opModes.removeAt(j);
1459 if (opModes.size() <= 0) {
1460 uidState.opModes = null;
1461 }
1462 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001463 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001464 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001465 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001466 mPackageModeWatchers.get(packageName));
1467 }
1468 }
1469 }
1470 }
1471
1472 if (uidState.pkgOps == null) {
1473 continue;
1474 }
1475
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001476 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001477 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001478 // Skip any ops for a different user
1479 continue;
1480 }
Svet Ganov2af57082015-07-30 08:44:20 -07001481
1482 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001483 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001484 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001485 while (it.hasNext()) {
1486 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001487 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001488 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1489 // Skip any ops for a different package
1490 continue;
1491 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001492 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001493 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001494 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001495 if (AppOpsManager.opAllowsReset(curOp.op)
1496 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001497 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001498 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001499 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001500 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001501 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001502 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001503 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001504 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001505 pkgOps.removeAt(j);
1506 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001507 }
1508 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001509 if (pkgOps.size() == 0) {
1510 it.remove();
1511 }
1512 }
Svet Ganov2af57082015-07-30 08:44:20 -07001513 if (uidState.isDefault()) {
1514 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001515 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001516 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001517 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001518 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001519 }
Svet Ganov2af57082015-07-30 08:44:20 -07001520
Dianne Hackborn607b4142013-08-02 18:10:10 -07001521 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001522 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001523 }
1524 }
1525 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001526 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1527 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001528 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001529 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001530 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001531 mHandler.sendMessage(PooledLambda.obtainMessage(
1532 AppOpsService::notifyOpChanged,
1533 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001534 }
1535 }
1536 }
1537 }
1538
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001539 private void evalAllForegroundOpsLocked() {
1540 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
1541 final UidState uidState = mUidStates.valueAt(uidi);
1542 if (uidState.foregroundOps != null) {
1543 uidState.evalForegroundOps(mOpModeWatchers);
1544 }
1545 }
1546 }
1547
Dianne Hackbornc2293022013-02-06 23:14:49 -08001548 @Override
1549 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001550 startWatchingModeWithFlags(op, packageName, 0, callback);
1551 }
1552
1553 @Override
1554 public void startWatchingModeWithFlags(int op, String packageName, int flags,
1555 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001556 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001557 final int callingUid = Binder.getCallingUid();
1558 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07001559 // TODO: should have a privileged permission to protect this.
1560 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
1561 // the USAGE_STATS permission since this can provide information about when an
1562 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001563 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1564 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001565 if (callback == null) {
1566 return;
1567 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001568 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001569 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001570 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001571 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001572 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001573 mModeWatchers.put(callback.asBinder(), cb);
1574 }
1575 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001576 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001577 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001578 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001579 mOpModeWatchers.put(op, cbs);
1580 }
1581 cbs.add(cb);
1582 }
1583 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001584 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001585 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001586 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001587 mPackageModeWatchers.put(packageName, cbs);
1588 }
1589 cbs.add(cb);
1590 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001591 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001592 }
1593 }
1594
1595 @Override
1596 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001597 if (callback == null) {
1598 return;
1599 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001600 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001601 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001602 if (cb != null) {
1603 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001604 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001605 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001606 cbs.remove(cb);
1607 if (cbs.size() <= 0) {
1608 mOpModeWatchers.removeAt(i);
1609 }
1610 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001611 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001612 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001613 cbs.remove(cb);
1614 if (cbs.size() <= 0) {
1615 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001616 }
1617 }
1618 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001619 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001620 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001621 }
1622
1623 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001624 public IBinder getToken(IBinder clientToken) {
1625 synchronized (this) {
1626 ClientState cs = mClients.get(clientToken);
1627 if (cs == null) {
1628 cs = new ClientState(clientToken);
1629 mClients.put(clientToken, cs);
1630 }
1631 return cs;
1632 }
1633 }
1634
Svet Ganovd873ae62018-06-25 16:39:23 -07001635 public CheckOpsDelegate getAppOpsServiceDelegate() {
1636 synchronized (this) {
1637 return mCheckOpsDelegate;
1638 }
1639 }
1640
1641 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
1642 synchronized (this) {
1643 mCheckOpsDelegate = delegate;
1644 }
1645 }
1646
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001647 @Override
Svet Ganov9d528a12018-12-19 17:23:11 -08001648 public int checkOperationRaw(int code, int uid, String packageName) {
1649 return checkOperationInternal(code, uid, packageName, true /*raw*/);
1650 }
1651
1652 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001653 public int checkOperation(int code, int uid, String packageName) {
Svet Ganov9d528a12018-12-19 17:23:11 -08001654 return checkOperationInternal(code, uid, packageName, false /*raw*/);
1655 }
1656
1657 private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001658 final CheckOpsDelegate delegate;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001659 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001660 delegate = mCheckOpsDelegate;
1661 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001662 if (delegate == null) {
Svet Ganov9d528a12018-12-19 17:23:11 -08001663 return checkOperationImpl(code, uid, packageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08001664 }
Svet Ganov9d528a12018-12-19 17:23:11 -08001665 return delegate.checkOperation(code, uid, packageName, raw,
Svet Ganovd873ae62018-06-25 16:39:23 -07001666 AppOpsService.this::checkOperationImpl);
1667 }
1668
Svet Ganov9d528a12018-12-19 17:23:11 -08001669 private int checkOperationImpl(int code, int uid, String packageName,
1670 boolean raw) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001671 verifyIncomingUid(uid);
1672 verifyIncomingOp(code);
1673 String resolvedPackageName = resolvePackageName(uid, packageName);
1674 if (resolvedPackageName == null) {
1675 return AppOpsManager.MODE_IGNORED;
1676 }
Svet Ganov9d528a12018-12-19 17:23:11 -08001677 return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08001678 }
1679
Svet Ganov9d528a12018-12-19 17:23:11 -08001680 private int checkOperationUnchecked(int code, int uid, String packageName,
1681 boolean raw) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001682 synchronized (this) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001683 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001684 return AppOpsManager.MODE_IGNORED;
1685 }
Svet Ganov2af57082015-07-30 08:44:20 -07001686 code = AppOpsManager.opToSwitch(code);
1687 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001688 if (uidState != null && uidState.opModes != null
1689 && uidState.opModes.indexOfKey(code) >= 0) {
Svet Ganov9d528a12018-12-19 17:23:11 -08001690 final int rawMode = uidState.opModes.get(code);
1691 return raw ? rawMode : uidState.evalMode(rawMode);
Svet Ganov2af57082015-07-30 08:44:20 -07001692 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001693 Op op = getOpLocked(code, uid, packageName, false, true, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001694 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001695 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001696 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001697 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001698 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001699 }
1700
1701 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001702 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001703 final CheckOpsDelegate delegate;
John Spurlock1af30c72014-03-10 08:33:35 -04001704 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001705 delegate = mCheckOpsDelegate;
1706 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001707 if (delegate == null) {
1708 return checkAudioOperationImpl(code, usage, uid, packageName);
1709 }
Svet Ganovd873ae62018-06-25 16:39:23 -07001710 return delegate.checkAudioOperation(code, usage, uid, packageName,
1711 AppOpsService.this::checkAudioOperationImpl);
1712 }
1713
1714 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
Todd Kennedy556efba2018-11-15 07:43:55 -08001715 boolean suspended;
1716 try {
1717 suspended = isPackageSuspendedForUser(packageName, uid);
1718 } catch (IllegalArgumentException ex) {
1719 // Package not found.
1720 suspended = false;
1721 }
1722
1723 if (suspended) {
1724 Slog.i(TAG, "Audio disabled for suspended package=" + packageName
1725 + " for uid=" + uid);
1726 return AppOpsManager.MODE_IGNORED;
1727 }
1728
Svet Ganovd873ae62018-06-25 16:39:23 -07001729 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001730 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001731 if (mode != AppOpsManager.MODE_ALLOWED) {
1732 return mode;
1733 }
1734 }
1735 return checkOperation(code, uid, packageName);
1736 }
1737
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001738 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001739 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001740 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1741 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001742 } catch (RemoteException re) {
1743 throw new SecurityException("Could not talk to package manager service");
1744 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001745 }
1746
John Spurlock7b414672014-07-18 13:02:39 -04001747 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1748 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1749 if (usageRestrictions != null) {
1750 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001751 if (r != null && !r.exceptionPackages.contains(packageName)) {
1752 return r.mode;
1753 }
1754 }
1755 return AppOpsManager.MODE_ALLOWED;
1756 }
1757
1758 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001759 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001760 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001761 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04001762 verifyIncomingUid(uid);
1763 verifyIncomingOp(code);
1764 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001765 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1766 if (usageRestrictions == null) {
1767 usageRestrictions = new SparseArray<Restriction>();
1768 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001769 }
John Spurlock7b414672014-07-18 13:02:39 -04001770 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001771 if (mode != AppOpsManager.MODE_ALLOWED) {
1772 final Restriction r = new Restriction();
1773 r.mode = mode;
1774 if (exceptionPackages != null) {
1775 final int N = exceptionPackages.length;
1776 r.exceptionPackages = new ArraySet<String>(N);
1777 for (int i = 0; i < N; i++) {
1778 final String pkg = exceptionPackages[i];
1779 if (pkg != null) {
1780 r.exceptionPackages.add(pkg.trim());
1781 }
1782 }
1783 }
John Spurlock7b414672014-07-18 13:02:39 -04001784 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001785 }
1786 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001787
1788 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001789 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001790 }
1791
1792 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001793 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001794 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001795 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001796 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1797 true /* uidMismatchExpected */);
1798 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001799 return AppOpsManager.MODE_ALLOWED;
1800 } else {
1801 return AppOpsManager.MODE_ERRORED;
1802 }
1803 }
1804 }
1805
1806 @Override
Svet Ganovd873ae62018-06-25 16:39:23 -07001807 public int noteProxyOperation(int code, int proxyUid,
1808 String proxyPackageName, int proxiedUid, String proxiedPackageName) {
1809 verifyIncomingUid(proxyUid);
Svet Ganov99b60432015-06-27 13:15:22 -07001810 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001811 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1812 if (resolveProxyPackageName == null) {
1813 return AppOpsManager.MODE_IGNORED;
1814 }
1815 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1816 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001817 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1818 return proxyMode;
1819 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001820 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1821 if (resolveProxiedPackageName == null) {
1822 return AppOpsManager.MODE_IGNORED;
1823 }
1824 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1825 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001826 }
1827
1828 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001829 public int noteOperation(int code, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001830 final CheckOpsDelegate delegate;
1831 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07001832 delegate = mCheckOpsDelegate;
1833 }
Todd Kennedy556efba2018-11-15 07:43:55 -08001834 if (delegate == null) {
1835 return noteOperationImpl(code, uid, packageName);
1836 }
Svet Ganovd873ae62018-06-25 16:39:23 -07001837 return delegate.noteOperation(code, uid, packageName,
1838 AppOpsService.this::noteOperationImpl);
1839 }
1840
1841 private int noteOperationImpl(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001842 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001843 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001844 String resolvedPackageName = resolvePackageName(uid, packageName);
1845 if (resolvedPackageName == null) {
1846 return AppOpsManager.MODE_IGNORED;
1847 }
1848 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001849 }
1850
1851 private int noteOperationUnchecked(int code, int uid, String packageName,
1852 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001853 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001854 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001855 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001856 if (ops == null) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001857 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1858 AppOpsManager.MODE_IGNORED);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001859 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001860 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001861 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001862 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001863 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001864 if (isOpRestrictedLocked(uid, code, packageName)) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001865 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1866 AppOpsManager.MODE_IGNORED);
Jason Monk62062992014-05-06 09:55:28 -04001867 return AppOpsManager.MODE_IGNORED;
1868 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001869 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001870 if (op.duration == -1) {
1871 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001872 + " code " + code + " time=" + op.time[uidState.state]
1873 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001874 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001875 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001876 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001877 // If there is a non-default per UID policy (we set UID op mode only if
1878 // non-default) it takes over, otherwise use the per package policy.
1879 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001880 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001881 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001882 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001883 + switchCode + " (" + code + ") uid " + uid + " package "
1884 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001885 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001886 scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
Svet Ganov2af57082015-07-30 08:44:20 -07001887 return uidMode;
1888 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001889 } else {
1890 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001891 final int mode = switchOp.getMode();
1892 if (mode != AppOpsManager.MODE_ALLOWED) {
1893 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001894 + switchCode + " (" + code + ") uid " + uid + " package "
1895 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001896 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001897 scheduleOpNotedIfNeededLocked(op.op, uid, packageName, mode);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001898 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001899 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001900 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001901 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001902 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001903 op.time[uidState.state] = System.currentTimeMillis();
1904 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001905 op.proxyUid = proxyUid;
1906 op.proxyPackageName = proxyPackageName;
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001907 scheduleOpNotedIfNeededLocked(code, uid, packageName,
1908 AppOpsManager.MODE_ALLOWED);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001909 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001910 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001911 }
1912
1913 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001914 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001915 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001916 final int callingUid = Binder.getCallingUid();
1917 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001918 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1919 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001920 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001921 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001922 if (ops != null) {
1923 Preconditions.checkArrayElementsInRange(ops, 0,
1924 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1925 }
1926 if (callback == null) {
1927 return;
1928 }
1929 synchronized (this) {
1930 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1931 if (callbacks == null) {
1932 callbacks = new SparseArray<>();
1933 mActiveWatchers.put(callback.asBinder(), callbacks);
1934 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001935 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1936 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001937 for (int op : ops) {
1938 callbacks.put(op, activeCallback);
1939 }
1940 }
1941 }
1942
1943 @Override
1944 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1945 if (callback == null) {
1946 return;
1947 }
1948 synchronized (this) {
1949 final SparseArray<ActiveCallback> activeCallbacks =
1950 mActiveWatchers.remove(callback.asBinder());
1951 if (activeCallbacks == null) {
1952 return;
1953 }
1954 final int callbackCount = activeCallbacks.size();
1955 for (int i = 0; i < callbackCount; i++) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001956 activeCallbacks.valueAt(i).destroy();
1957 }
1958 }
1959 }
1960
1961 @Override
1962 public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
1963 int watchedUid = Process.INVALID_UID;
1964 final int callingUid = Binder.getCallingUid();
1965 final int callingPid = Binder.getCallingPid();
1966 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1967 != PackageManager.PERMISSION_GRANTED) {
1968 watchedUid = callingUid;
1969 }
1970 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
1971 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
1972 "Invalid op code in: " + Arrays.toString(ops));
1973 Preconditions.checkNotNull(callback, "Callback cannot be null");
1974 synchronized (this) {
1975 SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
1976 if (callbacks == null) {
1977 callbacks = new SparseArray<>();
1978 mNotedWatchers.put(callback.asBinder(), callbacks);
1979 }
1980 final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
1981 callingUid, callingPid);
1982 for (int op : ops) {
1983 callbacks.put(op, notedCallback);
1984 }
1985 }
1986 }
1987
1988 @Override
1989 public void stopWatchingNoted(IAppOpsNotedCallback callback) {
1990 Preconditions.checkNotNull(callback, "Callback cannot be null");
1991 synchronized (this) {
1992 final SparseArray<NotedCallback> notedCallbacks =
1993 mNotedWatchers.remove(callback.asBinder());
1994 if (notedCallbacks == null) {
1995 return;
1996 }
1997 final int callbackCount = notedCallbacks.size();
1998 for (int i = 0; i < callbackCount; i++) {
1999 notedCallbacks.valueAt(i).destroy();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002000 }
2001 }
2002 }
2003
2004 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08002005 public int startOperation(IBinder token, int code, int uid, String packageName,
2006 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002007 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002008 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002009 String resolvedPackageName = resolvePackageName(uid, packageName);
2010 if (resolvedPackageName == null) {
2011 return AppOpsManager.MODE_IGNORED;
2012 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002013 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002014 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002015 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07002016 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002017 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002018 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002019 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002020 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002021 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002022 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07002023 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04002024 return AppOpsManager.MODE_IGNORED;
2025 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002026 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002027 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002028 // If there is a non-default per UID policy (we set UID op mode only if
2029 // non-default) it takes over, otherwise use the per package policy.
2030 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002031 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08002032 if (uidMode != AppOpsManager.MODE_ALLOWED
2033 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002034 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07002035 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002036 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002037 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07002038 return uidMode;
2039 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002040 } else {
2041 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002042 final int mode = switchOp.getMode();
2043 if (mode != AppOpsManager.MODE_ALLOWED
2044 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
2045 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002046 + switchCode + " (" + code + ") uid " + uid + " package "
2047 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002048 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002049 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002050 }
Svet Ganov2af57082015-07-30 08:44:20 -07002051 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002052 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002053 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002054 if (op.startNesting == 0) {
2055 op.startRealtime = SystemClock.elapsedRealtime();
2056 op.time[uidState.state] = System.currentTimeMillis();
2057 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002058 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002059 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002060 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002061 op.startNesting++;
2062 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002063 if (client.mStartedOps != null) {
2064 client.mStartedOps.add(op);
2065 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002066 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002067
2068 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002069 }
2070
2071 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002072 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002073 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002074 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002075 String resolvedPackageName = resolvePackageName(uid, packageName);
2076 if (resolvedPackageName == null) {
2077 return;
2078 }
2079 if (!(token instanceof ClientState)) {
2080 return;
2081 }
2082 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002083 synchronized (this) {
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002084 Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002085 if (op == null) {
2086 return;
2087 }
Svet Ganovf7b47252018-02-26 11:11:27 -08002088 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07002089 // We finish ops when packages get removed to guarantee no dangling
2090 // started ops. However, some part of the system may asynchronously
2091 // finish ops for an already gone package. Hence, finishing an op
2092 // for a non existing package is fine and we don't log as a wtf.
2093 final long identity = Binder.clearCallingIdentity();
2094 try {
2095 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
2096 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
2097 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
2098 + " for non-existing package=" + resolvedPackageName
2099 + " in uid=" + uid);
2100 return;
2101 }
2102 } finally {
2103 Binder.restoreCallingIdentity(identity);
2104 }
2105 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
2106 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07002107 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002108 }
Svet Ganova7a0db62018-02-27 20:08:01 -08002109 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002110 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002111 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
2112 }
2113 }
2114 }
2115
2116 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
2117 boolean active) {
2118 ArraySet<ActiveCallback> dispatchedCallbacks = null;
2119 final int callbackListCount = mActiveWatchers.size();
2120 for (int i = 0; i < callbackListCount; i++) {
2121 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
2122 ActiveCallback callback = callbacks.get(code);
2123 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002124 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08002125 continue;
2126 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002127 if (dispatchedCallbacks == null) {
2128 dispatchedCallbacks = new ArraySet<>();
2129 }
2130 dispatchedCallbacks.add(callback);
2131 }
2132 }
2133 if (dispatchedCallbacks == null) {
2134 return;
2135 }
2136 mHandler.sendMessage(PooledLambda.obtainMessage(
2137 AppOpsService::notifyOpActiveChanged,
2138 this, dispatchedCallbacks, code, uid, packageName, active));
2139 }
2140
2141 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
2142 int code, int uid, String packageName, boolean active) {
2143 // There are components watching for mode changes such as window manager
2144 // and location manager which are in our process. The callbacks in these
2145 // components may require permissions our remote caller does not have.
2146 final long identity = Binder.clearCallingIdentity();
2147 try {
2148 final int callbackCount = callbacks.size();
2149 for (int i = 0; i < callbackCount; i++) {
2150 final ActiveCallback callback = callbacks.valueAt(i);
2151 try {
2152 callback.mCallback.opActiveChanged(code, uid, packageName, active);
2153 } catch (RemoteException e) {
2154 /* do nothing */
2155 }
2156 }
2157 } finally {
2158 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002159 }
2160 }
2161
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002162 private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
2163 int result) {
2164 ArraySet<NotedCallback> dispatchedCallbacks = null;
2165 final int callbackListCount = mNotedWatchers.size();
2166 for (int i = 0; i < callbackListCount; i++) {
2167 final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
2168 final NotedCallback callback = callbacks.get(code);
2169 if (callback != null) {
2170 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
2171 continue;
2172 }
2173 if (dispatchedCallbacks == null) {
2174 dispatchedCallbacks = new ArraySet<>();
2175 }
2176 dispatchedCallbacks.add(callback);
2177 }
2178 }
2179 if (dispatchedCallbacks == null) {
2180 return;
2181 }
2182 mHandler.sendMessage(PooledLambda.obtainMessage(
2183 AppOpsService::notifyOpChecked,
2184 this, dispatchedCallbacks, code, uid, packageName, result));
2185 }
2186
2187 private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
2188 int code, int uid, String packageName, int result) {
2189 // There are components watching for checks in our process. The callbacks in
2190 // these components may require permissions our remote caller does not have.
2191 final long identity = Binder.clearCallingIdentity();
2192 try {
2193 final int callbackCount = callbacks.size();
2194 for (int i = 0; i < callbackCount; i++) {
2195 final NotedCallback callback = callbacks.valueAt(i);
2196 try {
2197 callback.mCallback.opNoted(code, uid, packageName, result);
2198 } catch (RemoteException e) {
2199 /* do nothing */
2200 }
2201 }
2202 } finally {
2203 Binder.restoreCallingIdentity(identity);
2204 }
2205 }
2206
Svet Ganovb9d71a62015-04-30 10:38:13 -07002207 @Override
2208 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002209 if (permission == null) {
2210 return AppOpsManager.OP_NONE;
2211 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07002212 return AppOpsManager.permissionToOpCode(permission);
2213 }
2214
Svet Ganova7a0db62018-02-27 20:08:01 -08002215 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002216 if (op.startNesting <= 1 || finishNested) {
2217 if (op.startNesting == 1 || finishNested) {
2218 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
2219 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002220 } else {
2221 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
2222 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002223 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002224 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002225 if (op.startNesting >= 1) {
2226 op.uidState.startNesting -= op.startNesting;
2227 }
2228 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002229 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002230 op.startNesting--;
2231 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002232 }
2233 }
2234
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002235 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002236 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002237 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002238 }
2239 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002240 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002241 }
2242 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
2243 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002244 }
2245
Dianne Hackborn961321f2013-02-05 17:22:41 -08002246 private void verifyIncomingOp(int op) {
2247 if (op >= 0 && op < AppOpsManager._NUM_OP) {
2248 return;
2249 }
2250 throw new IllegalArgumentException("Bad operation #" + op);
2251 }
2252
Svet Ganov2af57082015-07-30 08:44:20 -07002253 private UidState getUidStateLocked(int uid, boolean edit) {
2254 UidState uidState = mUidStates.get(uid);
2255 if (uidState == null) {
2256 if (!edit) {
2257 return null;
2258 }
2259 uidState = new UidState(uid);
2260 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002261 } else {
2262 if (uidState.pendingStateCommitTime != 0) {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002263 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002264 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002265 } else {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07002266 mLastRealtime = SystemClock.elapsedRealtime();
2267 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002268 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002269 }
2270 }
2271 }
Svet Ganov2af57082015-07-30 08:44:20 -07002272 }
2273 return uidState;
2274 }
2275
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002276 private void commitUidPendingStateLocked(UidState uidState) {
Dianne Hackborne93ab412018-05-14 17:52:30 -07002277 final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
2278 final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002279 uidState.state = uidState.pendingState;
2280 uidState.pendingStateCommitTime = 0;
Dianne Hackborne93ab412018-05-14 17:52:30 -07002281 if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002282 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
2283 if (!uidState.foregroundOps.valueAt(fgi)) {
2284 continue;
2285 }
2286 final int code = uidState.foregroundOps.keyAt(fgi);
2287
2288 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
2289 if (callbacks != null) {
2290 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
2291 final ModeCallback callback = callbacks.valueAt(cbi);
2292 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
2293 || !callback.isWatchingUid(uidState.uid)) {
2294 continue;
2295 }
2296 boolean doAllPackages = uidState.opModes != null
Hai Zhang2b98fb32018-09-21 15:18:46 -07002297 && uidState.opModes.indexOfKey(code) >= 0
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002298 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
2299 if (uidState.pkgOps != null) {
2300 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
2301 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
2302 if (doAllPackages || (op != null
2303 && op.mode == AppOpsManager.MODE_FOREGROUND)) {
2304 mHandler.sendMessage(PooledLambda.obtainMessage(
2305 AppOpsService::notifyOpChanged,
2306 this, callback, code, uidState.uid,
2307 uidState.pkgOps.keyAt(pkgi)));
2308 }
2309 }
2310 }
2311 }
2312 }
2313 }
2314 }
2315 }
2316
Yohei Yukawaa965d652017-10-12 15:02:26 -07002317 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
2318 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07002319 UidState uidState = getUidStateLocked(uid, edit);
2320 if (uidState == null) {
2321 return null;
2322 }
2323
2324 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002325 if (!edit) {
2326 return null;
2327 }
Svet Ganov2af57082015-07-30 08:44:20 -07002328 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002329 }
Svet Ganov2af57082015-07-30 08:44:20 -07002330
2331 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002332 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002333 if (!edit) {
2334 return null;
2335 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002336 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002337 // This is the first time we have seen this package name under this uid,
2338 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08002339 if (uid != 0) {
2340 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002341 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08002342 int pkgUid = -1;
2343 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04002344 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07002345 .getApplicationInfo(packageName,
Svet Ganovad0a49b2018-10-29 10:07:08 -07002346 PackageManager.MATCH_DIRECT_BOOT_AWARE
2347 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
Jeff Sharkeycd654482016-01-08 17:42:11 -07002348 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04002349 if (appInfo != null) {
2350 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002351 isPrivileged = (appInfo.privateFlags
2352 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002353 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002354 pkgUid = resolveUid(packageName);
2355 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08002356 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04002357 }
Dianne Hackborn713df152013-05-17 11:27:57 -07002358 }
Jason Monk1c7c3192014-06-26 12:52:18 -04002359 } catch (RemoteException e) {
2360 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08002361 }
2362 if (pkgUid != uid) {
2363 // Oops! The package name is not valid for the uid they are calling
2364 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07002365 if (!uidMismatchExpected) {
2366 RuntimeException ex = new RuntimeException("here");
2367 ex.fillInStackTrace();
2368 Slog.w(TAG, "Bad call: specified package " + packageName
2369 + " under uid " + uid + " but it is really " + pkgUid, ex);
2370 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08002371 return null;
2372 }
2373 } finally {
2374 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002375 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002376 }
Svet Ganov2af57082015-07-30 08:44:20 -07002377 ops = new Ops(packageName, uidState, isPrivileged);
2378 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002379 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08002380 return ops;
2381 }
2382
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002383 /**
2384 * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
2385 *
2386 * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
2387 *
2388 * @param uid The uid the of the package
2389 * @param packageName The package name for which to get the state for
2390 * @param edit Iff {@code true} create the {@link Ops} object if not yet created
2391 * @param isPrivileged Whether the package is privileged or not
2392 *
2393 * @return The {@link Ops state} of all ops for the package
2394 */
2395 private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
2396 boolean edit, boolean isPrivileged) {
2397 UidState uidState = getUidStateLocked(uid, edit);
2398 if (uidState == null) {
2399 return null;
2400 }
2401
2402 if (uidState.pkgOps == null) {
2403 if (!edit) {
2404 return null;
2405 }
2406 uidState.pkgOps = new ArrayMap<>();
2407 }
2408
2409 Ops ops = uidState.pkgOps.get(packageName);
2410 if (ops == null) {
2411 if (!edit) {
2412 return null;
2413 }
2414 ops = new Ops(packageName, uidState, isPrivileged);
2415 uidState.pkgOps.put(packageName, ops);
2416 }
2417 return ops;
2418 }
2419
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002420 private void scheduleWriteLocked() {
2421 if (!mWriteScheduled) {
2422 mWriteScheduled = true;
2423 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
2424 }
2425 }
2426
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002427 private void scheduleFastWriteLocked() {
2428 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002429 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002430 mFastWriteScheduled = true;
2431 mHandler.removeCallbacks(mWriteRunner);
2432 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002433 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002434 }
2435
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002436 /**
2437 * Get the state of an op for a uid.
2438 *
2439 * @param code The code of the op
2440 * @param uid The uid the of the package
2441 * @param packageName The package name for which to get the state for
2442 * @param edit Iff {@code true} create the {@link Op} object if not yet created
2443 * @param verifyUid Iff {@code true} check that the package belongs to the uid
2444 * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
2445 * == false})
2446 *
2447 * @return The {@link Op state} of the op
2448 */
2449 private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
2450 boolean verifyUid, boolean isPrivileged) {
2451 Ops ops;
2452
2453 if (verifyUid) {
2454 ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
2455 } else {
2456 ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
2457 }
2458
Dianne Hackborn72e39832013-01-18 18:36:09 -08002459 if (ops == null) {
2460 return null;
2461 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002462 return getOpLocked(ops, code, edit);
2463 }
2464
2465 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002466 Op op = ops.get(code);
2467 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002468 if (!edit) {
2469 return null;
2470 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002471 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002472 ops.put(code, op);
2473 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002474 if (edit) {
2475 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002476 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002477 return op;
2478 }
2479
Svet Ganov442ed572016-08-17 17:29:43 -07002480 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04002481 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002482 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08002483
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002484 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08002485 // For each client, check that the given op is not restricted, or that the given
2486 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002487 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002488 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
2489 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
2490 // If we are the system, bypass user restrictions for certain codes
2491 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002492 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
2493 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07002494 if ((ops != null) && ops.isPrivileged) {
2495 return false;
2496 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08002497 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002498 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002499 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04002500 }
Jason Monk62062992014-05-06 09:55:28 -04002501 }
2502 return false;
2503 }
2504
Dianne Hackborn35654b62013-01-14 17:38:02 -08002505 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002506 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002507 synchronized (mFile) {
2508 synchronized (this) {
2509 FileInputStream stream;
2510 try {
2511 stream = mFile.openRead();
2512 } catch (FileNotFoundException e) {
2513 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
2514 return;
2515 }
2516 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002517 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002518 try {
2519 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002520 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002521 int type;
2522 while ((type = parser.next()) != XmlPullParser.START_TAG
2523 && type != XmlPullParser.END_DOCUMENT) {
2524 ;
2525 }
2526
2527 if (type != XmlPullParser.START_TAG) {
2528 throw new IllegalStateException("no start tag found");
2529 }
2530
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002531 final String versionString = parser.getAttributeValue(null, "v");
2532 if (versionString != null) {
2533 oldVersion = Integer.parseInt(versionString);
2534 }
2535
Dianne Hackborn35654b62013-01-14 17:38:02 -08002536 int outerDepth = parser.getDepth();
2537 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2538 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2539 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2540 continue;
2541 }
2542
2543 String tagName = parser.getName();
2544 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002545 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07002546 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002547 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002548 } else {
2549 Slog.w(TAG, "Unknown element under <app-ops>: "
2550 + parser.getName());
2551 XmlUtils.skipCurrentTag(parser);
2552 }
2553 }
2554 success = true;
2555 } catch (IllegalStateException e) {
2556 Slog.w(TAG, "Failed parsing " + e);
2557 } catch (NullPointerException e) {
2558 Slog.w(TAG, "Failed parsing " + e);
2559 } catch (NumberFormatException e) {
2560 Slog.w(TAG, "Failed parsing " + e);
2561 } catch (XmlPullParserException e) {
2562 Slog.w(TAG, "Failed parsing " + e);
2563 } catch (IOException e) {
2564 Slog.w(TAG, "Failed parsing " + e);
2565 } catch (IndexOutOfBoundsException e) {
2566 Slog.w(TAG, "Failed parsing " + e);
2567 } finally {
2568 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07002569 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002570 }
2571 try {
2572 stream.close();
2573 } catch (IOException e) {
2574 }
2575 }
2576 }
2577 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002578 synchronized (this) {
2579 upgradeLocked(oldVersion);
2580 }
2581 }
2582
2583 private void upgradeRunAnyInBackgroundLocked() {
2584 for (int i = 0; i < mUidStates.size(); i++) {
2585 final UidState uidState = mUidStates.valueAt(i);
2586 if (uidState == null) {
2587 continue;
2588 }
2589 if (uidState.opModes != null) {
2590 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
2591 if (idx >= 0) {
2592 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
2593 uidState.opModes.valueAt(idx));
2594 }
2595 }
2596 if (uidState.pkgOps == null) {
2597 continue;
2598 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002599 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002600 for (int j = 0; j < uidState.pkgOps.size(); j++) {
2601 Ops ops = uidState.pkgOps.valueAt(j);
2602 if (ops != null) {
2603 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
2604 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002605 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002606 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
2607 copy.mode = op.mode;
2608 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002609 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002610 }
2611 }
2612 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002613 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002614 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002615 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002616 }
2617 }
2618
2619 private void upgradeLocked(int oldVersion) {
2620 if (oldVersion >= CURRENT_VERSION) {
2621 return;
2622 }
2623 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
2624 switch (oldVersion) {
2625 case NO_VERSION:
2626 upgradeRunAnyInBackgroundLocked();
2627 // fall through
2628 case 1:
2629 // for future upgrades
2630 }
2631 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002632 }
2633
Svet Ganov2af57082015-07-30 08:44:20 -07002634 void readUidOps(XmlPullParser parser) throws NumberFormatException,
2635 XmlPullParserException, IOException {
2636 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
2637 int outerDepth = parser.getDepth();
2638 int type;
2639 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2640 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2641 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2642 continue;
2643 }
2644
2645 String tagName = parser.getName();
2646 if (tagName.equals("op")) {
2647 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
2648 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
2649 UidState uidState = getUidStateLocked(uid, true);
2650 if (uidState.opModes == null) {
2651 uidState.opModes = new SparseIntArray();
2652 }
2653 uidState.opModes.put(code, mode);
2654 } else {
2655 Slog.w(TAG, "Unknown element under <uid-ops>: "
2656 + parser.getName());
2657 XmlUtils.skipCurrentTag(parser);
2658 }
2659 }
2660 }
2661
Dave Burke0997c5bd2013-08-02 20:25:02 +00002662 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002663 XmlPullParserException, IOException {
2664 String pkgName = parser.getAttributeValue(null, "n");
2665 int outerDepth = parser.getDepth();
2666 int type;
2667 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2668 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2669 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2670 continue;
2671 }
2672
2673 String tagName = parser.getName();
2674 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002675 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002676 } else {
2677 Slog.w(TAG, "Unknown element under <pkg>: "
2678 + parser.getName());
2679 XmlUtils.skipCurrentTag(parser);
2680 }
2681 }
2682 }
2683
Dave Burke0997c5bd2013-08-02 20:25:02 +00002684 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002685 XmlPullParserException, IOException {
2686 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002687 String isPrivilegedString = parser.getAttributeValue(null, "p");
2688 boolean isPrivileged = false;
2689 if (isPrivilegedString == null) {
2690 try {
2691 IPackageManager packageManager = ActivityThread.getPackageManager();
2692 if (packageManager != null) {
2693 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2694 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2695 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002696 isPrivileged = (appInfo.privateFlags
2697 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002698 }
2699 } else {
2700 // Could not load data, don't add to cache so it will be loaded later.
2701 return;
2702 }
2703 } catch (RemoteException e) {
2704 Slog.w(TAG, "Could not contact PackageManager", e);
2705 }
2706 } else {
2707 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2708 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002709 int outerDepth = parser.getDepth();
2710 int type;
2711 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2712 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2713 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2714 continue;
2715 }
2716
2717 String tagName = parser.getName();
2718 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002719 UidState uidState = getUidStateLocked(uid, true);
2720 if (uidState.pkgOps == null) {
2721 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002722 }
Svet Ganov2af57082015-07-30 08:44:20 -07002723
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002724 Op op = new Op(uidState, pkgName,
2725 Integer.parseInt(parser.getAttributeValue(null, "n")));
2726
2727 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2728 final String name = parser.getAttributeName(i);
2729 final String value = parser.getAttributeValue(i);
2730 switch (name) {
2731 case "m":
2732 op.mode = Integer.parseInt(value);
2733 break;
2734 case "d":
2735 op.duration = Integer.parseInt(value);
2736 break;
2737 case "pu":
2738 op.proxyUid = Integer.parseInt(value);
2739 break;
2740 case "pp":
2741 op.proxyPackageName = value;
2742 break;
2743 case "tp":
2744 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2745 break;
2746 case "tt":
2747 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2748 break;
2749 case "tfs":
2750 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2751 = Long.parseLong(value);
2752 break;
2753 case "tf":
2754 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2755 break;
2756 case "tb":
2757 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2758 break;
2759 case "tc":
2760 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2761 break;
2762 case "rp":
2763 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2764 = Long.parseLong(value);
2765 break;
2766 case "rt":
2767 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2768 break;
2769 case "rfs":
2770 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2771 = Long.parseLong(value);
2772 break;
2773 case "rf":
2774 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2775 = Long.parseLong(value);
2776 break;
2777 case "rb":
2778 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2779 = Long.parseLong(value);
2780 break;
2781 case "rc":
2782 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2783 = Long.parseLong(value);
2784 break;
2785 case "t":
2786 // Backwards compat.
2787 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2788 break;
2789 case "r":
2790 // Backwards compat.
2791 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2792 break;
2793 default:
2794 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2795 break;
2796 }
2797 }
2798
Svet Ganov2af57082015-07-30 08:44:20 -07002799 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002800 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002801 ops = new Ops(pkgName, uidState, isPrivileged);
2802 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002803 }
2804 ops.put(op.op, op);
2805 } else {
2806 Slog.w(TAG, "Unknown element under <pkg>: "
2807 + parser.getName());
2808 XmlUtils.skipCurrentTag(parser);
2809 }
2810 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002811 UidState uidState = getUidStateLocked(uid, false);
2812 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002813 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002814 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002815 }
2816
2817 void writeState() {
2818 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002819 FileOutputStream stream;
2820 try {
2821 stream = mFile.startWrite();
2822 } catch (IOException e) {
2823 Slog.w(TAG, "Failed to write state: " + e);
2824 return;
2825 }
2826
Dianne Hackborne17b4452018-01-10 13:15:40 -08002827 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2828
Dianne Hackborn35654b62013-01-14 17:38:02 -08002829 try {
2830 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002831 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002832 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002833 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002834 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002835
2836 final int uidStateCount = mUidStates.size();
2837 for (int i = 0; i < uidStateCount; i++) {
2838 UidState uidState = mUidStates.valueAt(i);
2839 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2840 out.startTag(null, "uid");
2841 out.attribute(null, "n", Integer.toString(uidState.uid));
2842 SparseIntArray uidOpModes = uidState.opModes;
2843 final int opCount = uidOpModes.size();
2844 for (int j = 0; j < opCount; j++) {
2845 final int op = uidOpModes.keyAt(j);
2846 final int mode = uidOpModes.valueAt(j);
2847 out.startTag(null, "op");
2848 out.attribute(null, "n", Integer.toString(op));
2849 out.attribute(null, "m", Integer.toString(mode));
2850 out.endTag(null, "op");
2851 }
2852 out.endTag(null, "uid");
2853 }
2854 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002855
2856 if (allOps != null) {
2857 String lastPkg = null;
2858 for (int i=0; i<allOps.size(); i++) {
2859 AppOpsManager.PackageOps pkg = allOps.get(i);
2860 if (!pkg.getPackageName().equals(lastPkg)) {
2861 if (lastPkg != null) {
2862 out.endTag(null, "pkg");
2863 }
2864 lastPkg = pkg.getPackageName();
2865 out.startTag(null, "pkg");
2866 out.attribute(null, "n", lastPkg);
2867 }
2868 out.startTag(null, "uid");
2869 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002870 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002871 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2872 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002873 // Should always be present as the list of PackageOps is generated
2874 // from Ops.
2875 if (ops != null) {
2876 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2877 } else {
2878 out.attribute(null, "p", Boolean.toString(false));
2879 }
2880 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002881 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2882 for (int j=0; j<ops.size(); j++) {
2883 AppOpsManager.OpEntry op = ops.get(j);
2884 out.startTag(null, "op");
2885 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002886 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002887 out.attribute(null, "m", Integer.toString(op.getMode()));
2888 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002889 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002890 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002891 if (time != 0) {
2892 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2893 Long.toString(time));
2894 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002895 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002896 if (rejectTime != 0) {
2897 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2898 Long.toString(rejectTime));
2899 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002900 }
2901 int dur = op.getDuration();
2902 if (dur != 0) {
2903 out.attribute(null, "d", Integer.toString(dur));
2904 }
Svet Ganov99b60432015-06-27 13:15:22 -07002905 int proxyUid = op.getProxyUid();
2906 if (proxyUid != -1) {
2907 out.attribute(null, "pu", Integer.toString(proxyUid));
2908 }
2909 String proxyPackageName = op.getProxyPackageName();
2910 if (proxyPackageName != null) {
2911 out.attribute(null, "pp", proxyPackageName);
2912 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002913 out.endTag(null, "op");
2914 }
2915 out.endTag(null, "uid");
2916 }
2917 if (lastPkg != null) {
2918 out.endTag(null, "pkg");
2919 }
2920 }
2921
2922 out.endTag(null, "app-ops");
2923 out.endDocument();
2924 mFile.finishWrite(stream);
2925 } catch (IOException e) {
2926 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2927 mFile.failWrite(stream);
2928 }
2929 }
2930 }
2931
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002932 static class Shell extends ShellCommand {
2933 final IAppOpsService mInterface;
2934 final AppOpsService mInternal;
2935
2936 int userId = UserHandle.USER_SYSTEM;
2937 String packageName;
2938 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002939 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002940 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002941 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002942 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002943 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002944 final static Binder sBinder = new Binder();
2945 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002946
2947 Shell(IAppOpsService iface, AppOpsService internal) {
2948 mInterface = iface;
2949 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002950 try {
2951 mToken = mInterface.getToken(sBinder);
2952 } catch (RemoteException e) {
2953 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002954 }
2955
2956 @Override
2957 public int onCommand(String cmd) {
2958 return onShellCommand(this, cmd);
2959 }
2960
2961 @Override
2962 public void onHelp() {
2963 PrintWriter pw = getOutPrintWriter();
2964 dumpCommandHelp(pw);
2965 }
2966
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002967 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002968 try {
2969 return AppOpsManager.strOpToOp(op);
2970 } catch (IllegalArgumentException e) {
2971 }
2972 try {
2973 return Integer.parseInt(op);
2974 } catch (NumberFormatException e) {
2975 }
2976 try {
2977 return AppOpsManager.strDebugOpToOp(op);
2978 } catch (IllegalArgumentException e) {
2979 err.println("Error: " + e.getMessage());
2980 return -1;
2981 }
2982 }
2983
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002984 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002985 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2986 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002987 return i;
2988 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002989 }
2990 try {
2991 return Integer.parseInt(modeStr);
2992 } catch (NumberFormatException e) {
2993 }
2994 err.println("Error: Mode " + modeStr + " is not valid");
2995 return -1;
2996 }
2997
2998 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2999 userId = UserHandle.USER_CURRENT;
3000 opStr = null;
3001 modeStr = null;
3002 for (String argument; (argument = getNextArg()) != null;) {
3003 if ("--user".equals(argument)) {
3004 userId = UserHandle.parseUserArg(getNextArgRequired());
3005 } else {
3006 if (opStr == null) {
3007 opStr = argument;
3008 } else if (modeStr == null) {
3009 modeStr = argument;
3010 break;
3011 }
3012 }
3013 }
3014 if (opStr == null) {
3015 err.println("Error: Operation not specified.");
3016 return -1;
3017 }
3018 op = strOpToOp(opStr, err);
3019 if (op < 0) {
3020 return -1;
3021 }
3022 if (modeStr != null) {
3023 if ((mode=strModeToMode(modeStr, err)) < 0) {
3024 return -1;
3025 }
3026 } else {
3027 mode = defMode;
3028 }
3029 return 0;
3030 }
3031
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003032 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
3033 userId = UserHandle.USER_CURRENT;
3034 packageName = null;
3035 opStr = null;
3036 for (String argument; (argument = getNextArg()) != null;) {
3037 if ("--user".equals(argument)) {
3038 userId = UserHandle.parseUserArg(getNextArgRequired());
3039 } else {
3040 if (packageName == null) {
3041 packageName = argument;
3042 } else if (opStr == null) {
3043 opStr = argument;
3044 break;
3045 }
3046 }
3047 }
3048 if (packageName == null) {
3049 err.println("Error: Package name not specified.");
3050 return -1;
3051 } else if (opStr == null && reqOp) {
3052 err.println("Error: Operation not specified.");
3053 return -1;
3054 }
3055 if (opStr != null) {
3056 op = strOpToOp(opStr, err);
3057 if (op < 0) {
3058 return -1;
3059 }
3060 } else {
3061 op = AppOpsManager.OP_NONE;
3062 }
3063 if (userId == UserHandle.USER_CURRENT) {
3064 userId = ActivityManager.getCurrentUser();
3065 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003066 nonpackageUid = -1;
3067 try {
3068 nonpackageUid = Integer.parseInt(packageName);
3069 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003070 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003071 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
3072 && packageName.indexOf('.') < 0) {
3073 int i = 1;
3074 while (i < packageName.length() && packageName.charAt(i) >= '0'
3075 && packageName.charAt(i) <= '9') {
3076 i++;
3077 }
3078 if (i > 1 && i < packageName.length()) {
3079 String userStr = packageName.substring(1, i);
3080 try {
3081 int user = Integer.parseInt(userStr);
3082 char type = packageName.charAt(i);
3083 i++;
3084 int startTypeVal = i;
3085 while (i < packageName.length() && packageName.charAt(i) >= '0'
3086 && packageName.charAt(i) <= '9') {
3087 i++;
3088 }
3089 if (i > startTypeVal) {
3090 String typeValStr = packageName.substring(startTypeVal, i);
3091 try {
3092 int typeVal = Integer.parseInt(typeValStr);
3093 if (type == 'a') {
3094 nonpackageUid = UserHandle.getUid(user,
3095 typeVal + Process.FIRST_APPLICATION_UID);
3096 } else if (type == 's') {
3097 nonpackageUid = UserHandle.getUid(user, typeVal);
3098 }
3099 } catch (NumberFormatException e) {
3100 }
3101 }
3102 } catch (NumberFormatException e) {
3103 }
3104 }
3105 }
3106 if (nonpackageUid != -1) {
3107 packageName = null;
3108 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003109 packageUid = resolveUid(packageName);
3110 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003111 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
3112 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
3113 }
3114 if (packageUid < 0) {
3115 err.println("Error: No UID for " + packageName + " in user " + userId);
3116 return -1;
3117 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003118 }
3119 return 0;
3120 }
3121 }
3122
3123 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07003124 FileDescriptor err, String[] args, ShellCallback callback,
3125 ResultReceiver resultReceiver) {
3126 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003127 }
3128
3129 static void dumpCommandHelp(PrintWriter pw) {
3130 pw.println("AppOps service (appops) commands:");
3131 pw.println(" help");
3132 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003133 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
3134 pw.println(" Starts a given operation for a particular application.");
3135 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
3136 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003137 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003138 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003139 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003140 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003141 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
3142 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003143 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
3144 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003145 pw.println(" write-settings");
3146 pw.println(" Immediately write pending changes to storage.");
3147 pw.println(" read-settings");
3148 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003149 pw.println(" options:");
3150 pw.println(" <PACKAGE> an Android package name.");
3151 pw.println(" <OP> an AppOps operation.");
3152 pw.println(" <MODE> one of allow, ignore, deny, or default");
3153 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
3154 pw.println(" specified, the current user is assumed.");
3155 }
3156
3157 static int onShellCommand(Shell shell, String cmd) {
3158 if (cmd == null) {
3159 return shell.handleDefaultCommands(cmd);
3160 }
3161 PrintWriter pw = shell.getOutPrintWriter();
3162 PrintWriter err = shell.getErrPrintWriter();
3163 try {
3164 switch (cmd) {
3165 case "set": {
3166 int res = shell.parseUserPackageOp(true, err);
3167 if (res < 0) {
3168 return res;
3169 }
3170 String modeStr = shell.getNextArg();
3171 if (modeStr == null) {
3172 err.println("Error: Mode not specified.");
3173 return -1;
3174 }
3175
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003176 final int mode = shell.strModeToMode(modeStr, err);
3177 if (mode < 0) {
3178 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003179 }
3180
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003181 if (shell.packageName != null) {
3182 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
3183 mode);
3184 } else {
3185 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
3186 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003187 return 0;
3188 }
3189 case "get": {
3190 int res = shell.parseUserPackageOp(false, err);
3191 if (res < 0) {
3192 return res;
3193 }
3194
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003195 List<AppOpsManager.PackageOps> ops = new ArrayList<>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003196 if (shell.packageName != null) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003197 // Uid mode overrides package mode, so make sure it's also reported
3198 List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
3199 shell.packageUid,
3200 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3201 if (r != null) {
3202 ops.addAll(r);
3203 }
3204 r = shell.mInterface.getOpsForPackage(
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003205 shell.packageUid, shell.packageName,
3206 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003207 if (r != null) {
3208 ops.addAll(r);
3209 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07003210 } else {
3211 ops = shell.mInterface.getUidOps(
3212 shell.nonpackageUid,
3213 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
3214 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003215 if (ops == null || ops.size() <= 0) {
3216 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08003217 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003218 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08003219 AppOpsManager.opToDefaultMode(shell.op)));
3220 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003221 return 0;
3222 }
3223 final long now = System.currentTimeMillis();
3224 for (int i=0; i<ops.size(); i++) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08003225 AppOpsManager.PackageOps packageOps = ops.get(i);
3226 if (packageOps.getPackageName() == null) {
3227 pw.print("Uid mode: ");
3228 }
3229 List<AppOpsManager.OpEntry> entries = packageOps.getOps();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003230 for (int j=0; j<entries.size(); j++) {
3231 AppOpsManager.OpEntry ent = entries.get(j);
3232 pw.print(AppOpsManager.opToName(ent.getOp()));
3233 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003234 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003235 if (ent.getTime() != 0) {
3236 pw.print("; time=");
3237 TimeUtils.formatDuration(now - ent.getTime(), pw);
3238 pw.print(" ago");
3239 }
3240 if (ent.getRejectTime() != 0) {
3241 pw.print("; rejectTime=");
3242 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
3243 pw.print(" ago");
3244 }
3245 if (ent.getDuration() == -1) {
3246 pw.print(" (running)");
3247 } else if (ent.getDuration() != 0) {
3248 pw.print("; duration=");
3249 TimeUtils.formatDuration(ent.getDuration(), pw);
3250 }
3251 pw.println();
3252 }
3253 }
3254 return 0;
3255 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07003256 case "query-op": {
3257 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
3258 if (res < 0) {
3259 return res;
3260 }
3261 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
3262 new int[] {shell.op});
3263 if (ops == null || ops.size() <= 0) {
3264 pw.println("No operations.");
3265 return 0;
3266 }
3267 for (int i=0; i<ops.size(); i++) {
3268 final AppOpsManager.PackageOps pkg = ops.get(i);
3269 boolean hasMatch = false;
3270 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
3271 for (int j=0; j<entries.size(); j++) {
3272 AppOpsManager.OpEntry ent = entries.get(j);
3273 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
3274 hasMatch = true;
3275 break;
3276 }
3277 }
3278 if (hasMatch) {
3279 pw.println(pkg.getPackageName());
3280 }
3281 }
3282 return 0;
3283 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003284 case "reset": {
3285 String packageName = null;
3286 int userId = UserHandle.USER_CURRENT;
3287 for (String argument; (argument = shell.getNextArg()) != null;) {
3288 if ("--user".equals(argument)) {
3289 String userStr = shell.getNextArgRequired();
3290 userId = UserHandle.parseUserArg(userStr);
3291 } else {
3292 if (packageName == null) {
3293 packageName = argument;
3294 } else {
3295 err.println("Error: Unsupported argument: " + argument);
3296 return -1;
3297 }
3298 }
3299 }
3300
3301 if (userId == UserHandle.USER_CURRENT) {
3302 userId = ActivityManager.getCurrentUser();
3303 }
3304
3305 shell.mInterface.resetAllModes(userId, packageName);
3306 pw.print("Reset all modes for: ");
3307 if (userId == UserHandle.USER_ALL) {
3308 pw.print("all users");
3309 } else {
3310 pw.print("user "); pw.print(userId);
3311 }
3312 pw.print(", ");
3313 if (packageName == null) {
3314 pw.println("all packages");
3315 } else {
3316 pw.print("package "); pw.println(packageName);
3317 }
3318 return 0;
3319 }
3320 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003321 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3322 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003323 long token = Binder.clearCallingIdentity();
3324 try {
3325 synchronized (shell.mInternal) {
3326 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
3327 }
3328 shell.mInternal.writeState();
3329 pw.println("Current settings written.");
3330 } finally {
3331 Binder.restoreCallingIdentity(token);
3332 }
3333 return 0;
3334 }
3335 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07003336 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
3337 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003338 long token = Binder.clearCallingIdentity();
3339 try {
3340 shell.mInternal.readState();
3341 pw.println("Last settings read.");
3342 } finally {
3343 Binder.restoreCallingIdentity(token);
3344 }
3345 return 0;
3346 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05003347 case "start": {
3348 int res = shell.parseUserPackageOp(true, err);
3349 if (res < 0) {
3350 return res;
3351 }
3352
3353 if (shell.packageName != null) {
3354 shell.mInterface.startOperation(shell.mToken,
3355 shell.op, shell.packageUid, shell.packageName, true);
3356 } else {
3357 return -1;
3358 }
3359 return 0;
3360 }
3361 case "stop": {
3362 int res = shell.parseUserPackageOp(true, err);
3363 if (res < 0) {
3364 return res;
3365 }
3366
3367 if (shell.packageName != null) {
3368 shell.mInterface.finishOperation(shell.mToken,
3369 shell.op, shell.packageUid, shell.packageName);
3370 } else {
3371 return -1;
3372 }
3373 return 0;
3374 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08003375 default:
3376 return shell.handleDefaultCommands(cmd);
3377 }
3378 } catch (RemoteException e) {
3379 pw.println("Remote exception: " + e);
3380 }
3381 return -1;
3382 }
3383
3384 private void dumpHelp(PrintWriter pw) {
3385 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003386 pw.println(" -h");
3387 pw.println(" Print this help text.");
3388 pw.println(" --op [OP]");
3389 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003390 pw.println(" --mode [MODE]");
3391 pw.println(" Limit output to data associated with the given app op mode.");
3392 pw.println(" --package [PACKAGE]");
3393 pw.println(" Limit output to data associated with the given package name.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003394 }
3395
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003396 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
3397 long now, SimpleDateFormat sdf, Date date) {
3398 boolean hasTime = false;
3399 for (int i = 0; i < _NUM_UID_STATE; i++) {
3400 if (times[i] != 0) {
3401 hasTime = true;
3402 break;
3403 }
3404 }
3405 if (!hasTime) {
3406 return;
3407 }
3408 boolean first = true;
3409 for (int i = 0; i < _NUM_UID_STATE; i++) {
3410 if (times[i] != 0) {
3411 pw.print(first ? firstPrefix : prefix);
3412 first = false;
3413 pw.print(UID_STATE_NAMES[i]);
3414 pw.print(" = ");
3415 date.setTime(times[i]);
3416 pw.print(sdf.format(date));
3417 pw.print(" (");
3418 TimeUtils.formatDuration(times[i]-now, pw);
3419 pw.println(")");
3420 }
3421 }
3422 }
3423
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003424 @Override
3425 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003426 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003427
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003428 int dumpOp = -1;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003429 String dumpPackage = null;
3430 int dumpUid = -1;
3431 int dumpMode = -1;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003432
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003433 if (args != null) {
3434 for (int i=0; i<args.length; i++) {
3435 String arg = args[i];
3436 if ("-h".equals(arg)) {
3437 dumpHelp(pw);
3438 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07003439 } else if ("-a".equals(arg)) {
3440 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003441 } else if ("--op".equals(arg)) {
3442 i++;
3443 if (i >= args.length) {
3444 pw.println("No argument for --op option");
3445 return;
3446 }
3447 dumpOp = Shell.strOpToOp(args[i], pw);
3448 if (dumpOp < 0) {
3449 return;
3450 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003451 } else if ("--package".equals(arg)) {
3452 i++;
3453 if (i >= args.length) {
3454 pw.println("No argument for --package option");
3455 return;
3456 }
3457 dumpPackage = args[i];
3458 try {
3459 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
3460 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
3461 0);
3462 } catch (RemoteException e) {
3463 }
3464 if (dumpUid < 0) {
3465 pw.println("Unknown package: " + dumpPackage);
3466 return;
3467 }
3468 dumpUid = UserHandle.getAppId(dumpUid);
3469 } else if ("--mode".equals(arg)) {
3470 i++;
3471 if (i >= args.length) {
3472 pw.println("No argument for --mode option");
3473 return;
3474 }
3475 dumpMode = Shell.strModeToMode(args[i], pw);
3476 if (dumpMode < 0) {
3477 return;
3478 }
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003479 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
3480 pw.println("Unknown option: " + arg);
3481 return;
3482 } else {
3483 pw.println("Unknown command: " + arg);
3484 return;
3485 }
3486 }
3487 }
3488
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003489 synchronized (this) {
3490 pw.println("Current AppOps Service state:");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003491 mConstants.dump(pw);
3492 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003493 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003494 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003495 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003496 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
3497 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003498 boolean needSep = false;
Dianne Hackbornd5254412018-05-11 18:02:58 -07003499 if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
3500 pw.println(" Profile owners:");
3501 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
3502 pw.print(" User #");
3503 pw.print(mProfileOwners.keyAt(poi));
3504 pw.print(": ");
3505 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
3506 pw.println();
3507 }
3508 pw.println();
3509 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003510 if (mOpModeWatchers.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003511 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003512 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003513 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
3514 continue;
3515 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003516 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003517 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003518 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003519 final ModeCallback cb = callbacks.valueAt(j);
3520 if (dumpPackage != null && cb.mWatchingUid >= 0
3521 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3522 continue;
3523 }
3524 needSep = true;
3525 if (!printedHeader) {
3526 pw.println(" Op mode watchers:");
3527 printedHeader = true;
3528 }
3529 if (!printedOpHeader) {
3530 pw.print(" Op ");
3531 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
3532 pw.println(":");
3533 printedOpHeader = true;
3534 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003535 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003536 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003537 }
3538 }
3539 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003540 if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
3541 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003542 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003543 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
3544 continue;
3545 }
3546 needSep = true;
3547 if (!printedHeader) {
3548 pw.println(" Package mode watchers:");
3549 printedHeader = true;
3550 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003551 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
3552 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003553 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003554 for (int j=0; j<callbacks.size(); j++) {
3555 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08003556 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003557 }
3558 }
3559 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003560 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003561 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003562 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003563 final ModeCallback cb = mModeWatchers.valueAt(i);
3564 if (dumpPackage != null && cb.mWatchingUid >= 0
3565 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3566 continue;
3567 }
3568 needSep = true;
3569 if (!printedHeader) {
3570 pw.println(" All op mode watchers:");
3571 printedHeader = true;
3572 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003573 pw.print(" ");
3574 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003575 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003576 }
3577 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003578 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003579 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003580 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003581 for (int i = 0; i < mActiveWatchers.size(); i++) {
3582 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
3583 if (activeWatchers.size() <= 0) {
3584 continue;
3585 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003586 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003587 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
3588 continue;
3589 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003590 if (dumpPackage != null && cb.mWatchingUid >= 0
3591 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3592 continue;
3593 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003594 if (!printedHeader) {
3595 pw.println(" All op active watchers:");
3596 printedHeader = true;
3597 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003598 pw.print(" ");
3599 pw.print(Integer.toHexString(System.identityHashCode(
3600 mActiveWatchers.keyAt(i))));
3601 pw.println(" ->");
3602 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003603 final int opCount = activeWatchers.size();
3604 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003605 if (i > 0) {
3606 pw.print(' ');
3607 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003608 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
3609 if (i < opCount - 1) {
3610 pw.print(',');
3611 }
3612 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003613 pw.println("]");
3614 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003615 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003616 }
3617 }
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003618 if (mNotedWatchers.size() > 0 && dumpMode < 0) {
3619 needSep = true;
3620 boolean printedHeader = false;
3621 for (int i = 0; i < mNotedWatchers.size(); i++) {
3622 final SparseArray<NotedCallback> notedWatchers = mNotedWatchers.valueAt(i);
3623 if (notedWatchers.size() <= 0) {
3624 continue;
3625 }
3626 final NotedCallback cb = notedWatchers.valueAt(0);
3627 if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
3628 continue;
3629 }
3630 if (dumpPackage != null && cb.mWatchingUid >= 0
3631 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
3632 continue;
3633 }
3634 if (!printedHeader) {
3635 pw.println(" All op noted watchers:");
3636 printedHeader = true;
3637 }
3638 pw.print(" ");
3639 pw.print(Integer.toHexString(System.identityHashCode(
3640 mNotedWatchers.keyAt(i))));
3641 pw.println(" ->");
3642 pw.print(" [");
3643 final int opCount = notedWatchers.size();
3644 for (i = 0; i < opCount; i++) {
3645 if (i > 0) {
3646 pw.print(' ');
3647 }
3648 pw.print(AppOpsManager.opToName(notedWatchers.keyAt(i)));
3649 if (i < opCount - 1) {
3650 pw.print(',');
3651 }
3652 }
3653 pw.println("]");
3654 pw.print(" ");
3655 pw.println(cb);
3656 }
3657 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003658 if (mClients.size() > 0 && dumpMode < 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003659 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003660 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003661 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003662 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003663 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08003664 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003665 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003666 for (int j=0; j<cs.mStartedOps.size(); j++) {
3667 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003668 if (dumpOp >= 0 && op.op != dumpOp) {
3669 continue;
3670 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003671 if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
3672 continue;
3673 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003674 if (!printedHeader) {
3675 pw.println(" Clients:");
3676 printedHeader = true;
3677 }
3678 if (!printedClient) {
3679 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
3680 pw.print(" "); pw.println(cs);
3681 printedClient = true;
3682 }
3683 if (!printedStarted) {
3684 pw.println(" Started ops:");
3685 printedStarted = true;
3686 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003687 pw.print(" "); pw.print("uid="); pw.print(op.uid);
3688 pw.print(" pkg="); pw.print(op.packageName);
3689 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
3690 }
3691 }
3692 }
3693 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003694 if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
3695 && dumpMode < 0) {
John Spurlock1af30c72014-03-10 08:33:35 -04003696 boolean printedHeader = false;
3697 for (int o=0; o<mAudioRestrictions.size(); o++) {
3698 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
3699 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
3700 for (int i=0; i<restrictions.size(); i++) {
3701 if (!printedHeader){
3702 pw.println(" Audio Restrictions:");
3703 printedHeader = true;
3704 needSep = true;
3705 }
John Spurlock7b414672014-07-18 13:02:39 -04003706 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04003707 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04003708 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04003709 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003710 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04003711 if (!r.exceptionPackages.isEmpty()) {
3712 pw.println(" Exceptions:");
3713 for (int j=0; j<r.exceptionPackages.size(); j++) {
3714 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
3715 }
3716 }
3717 }
3718 }
3719 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003720 if (needSep) {
3721 pw.println();
3722 }
Svet Ganov2af57082015-07-30 08:44:20 -07003723 for (int i=0; i<mUidStates.size(); i++) {
3724 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003725 final SparseIntArray opModes = uidState.opModes;
3726 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
3727
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003728 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
3729 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
3730 && uidState.opModes.indexOfKey(dumpOp) >= 0);
3731 boolean hasPackage = dumpPackage == null;
3732 boolean hasMode = dumpMode < 0;
3733 if (!hasMode && opModes != null) {
3734 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
3735 if (opModes.valueAt(opi) == dumpMode) {
3736 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003737 }
3738 }
3739 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003740 if (pkgOps != null) {
3741 for (int pkgi = 0;
3742 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
3743 pkgi++) {
3744 Ops ops = pkgOps.valueAt(pkgi);
3745 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
3746 hasOp = true;
3747 }
3748 if (!hasMode) {
3749 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
3750 if (ops.valueAt(opi).mode == dumpMode) {
3751 hasMode = true;
3752 }
3753 }
3754 }
3755 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
3756 hasPackage = true;
3757 }
3758 }
3759 }
3760 if (uidState.foregroundOps != null && !hasOp) {
3761 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
3762 hasOp = true;
3763 }
3764 }
3765 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003766 continue;
3767 }
3768 }
Svet Ganov2af57082015-07-30 08:44:20 -07003769
3770 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003771 pw.print(" state=");
3772 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003773 if (uidState.state != uidState.pendingState) {
3774 pw.print(" pendingState=");
3775 pw.println(UID_STATE_NAMES[uidState.pendingState]);
3776 }
3777 if (uidState.pendingStateCommitTime != 0) {
3778 pw.print(" pendingStateCommitTime=");
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003779 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003780 pw.println();
3781 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003782 if (uidState.startNesting != 0) {
3783 pw.print(" startNesting=");
3784 pw.println(uidState.startNesting);
3785 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003786 if (uidState.foregroundOps != null && (dumpMode < 0
3787 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003788 pw.println(" foregroundOps:");
3789 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003790 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
3791 continue;
3792 }
3793 pw.print(" ");
3794 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
3795 pw.print(": ");
3796 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003797 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003798 pw.print(" hasForegroundWatchers=");
3799 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003800 }
Svet Ganovee438d42017-01-19 18:04:38 -08003801 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07003802
Svet Ganov2af57082015-07-30 08:44:20 -07003803 if (opModes != null) {
3804 final int opModeCount = opModes.size();
3805 for (int j = 0; j < opModeCount; j++) {
3806 final int code = opModes.keyAt(j);
3807 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003808 if (dumpOp >= 0 && dumpOp != code) {
3809 continue;
3810 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003811 if (dumpMode >= 0 && dumpMode != mode) {
3812 continue;
3813 }
Svet Ganov2af57082015-07-30 08:44:20 -07003814 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003815 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07003816 }
3817 }
3818
Svet Ganov2af57082015-07-30 08:44:20 -07003819 if (pkgOps == null) {
3820 continue;
3821 }
3822
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003823 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003824 final Ops ops = pkgOps.valueAt(pkgi);
3825 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
3826 continue;
3827 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003828 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003829 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003830 final Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003831 if (dumpOp >= 0 && dumpOp != op.op) {
3832 continue;
3833 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003834 if (dumpMode >= 0 && dumpMode != op.mode) {
3835 continue;
3836 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003837 if (!printedPackage) {
3838 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3839 printedPackage = true;
3840 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003841 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003842 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003843 final int switchOp = AppOpsManager.opToSwitch(op.op);
3844 if (switchOp != op.op) {
3845 pw.print(" / switch ");
3846 pw.print(AppOpsManager.opToName(switchOp));
3847 final Op switchObj = ops.get(switchOp);
3848 int mode = switchObj != null
3849 ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
3850 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
3851 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003852 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003853 dumpTimesLocked(pw,
3854 " Access: ",
3855 " ", op.time, now, sdf, date);
3856 dumpTimesLocked(pw,
3857 " Reject: ",
3858 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003859 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003860 pw.print(" Running start at: ");
3861 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3862 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003863 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003864 pw.print(" duration=");
3865 TimeUtils.formatDuration(op.duration, pw);
3866 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003867 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003868 if (op.startNesting != 0) {
3869 pw.print(" startNesting=");
3870 pw.println(op.startNesting);
3871 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003872 }
3873 }
3874 }
Svet Ganovee438d42017-01-19 18:04:38 -08003875 if (needSep) {
3876 pw.println();
3877 }
3878
3879 final int userRestrictionCount = mOpUserRestrictions.size();
3880 for (int i = 0; i < userRestrictionCount; i++) {
3881 IBinder token = mOpUserRestrictions.keyAt(i);
3882 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
3883 pw.println(" User restrictions for token " + token + ":");
3884
3885 final int restrictionCount = restrictionState.perUserRestrictions != null
3886 ? restrictionState.perUserRestrictions.size() : 0;
3887 if (restrictionCount > 0) {
3888 pw.println(" Restricted ops:");
3889 for (int j = 0; j < restrictionCount; j++) {
3890 int userId = restrictionState.perUserRestrictions.keyAt(j);
3891 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3892 if (restrictedOps == null) {
3893 continue;
3894 }
3895 StringBuilder restrictedOpsValue = new StringBuilder();
3896 restrictedOpsValue.append("[");
3897 final int restrictedOpCount = restrictedOps.length;
3898 for (int k = 0; k < restrictedOpCount; k++) {
3899 if (restrictedOps[k]) {
3900 if (restrictedOpsValue.length() > 1) {
3901 restrictedOpsValue.append(", ");
3902 }
3903 restrictedOpsValue.append(AppOpsManager.opToName(k));
3904 }
3905 }
3906 restrictedOpsValue.append("]");
3907 pw.print(" "); pw.print("user: "); pw.print(userId);
3908 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3909 }
3910 }
3911
3912 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3913 ? restrictionState.perUserExcludedPackages.size() : 0;
3914 if (excludedPackageCount > 0) {
3915 pw.println(" Excluded packages:");
3916 for (int j = 0; j < excludedPackageCount; j++) {
3917 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3918 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
3919 pw.print(" "); pw.print("user: "); pw.print(userId);
3920 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3921 }
3922 }
3923 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003924 }
3925 }
John Spurlock1af30c72014-03-10 08:33:35 -04003926
3927 private static final class Restriction {
3928 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3929 int mode;
3930 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3931 }
Jason Monk62062992014-05-06 09:55:28 -04003932
3933 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003934 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003935 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003936 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003937 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003938 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003939 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003940 if (restriction != null) {
3941 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
3942 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003943 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003944 }
3945 }
3946
3947 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08003948 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
3949 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003950 if (Binder.getCallingPid() != Process.myPid()) {
3951 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
3952 Binder.getCallingPid(), Binder.getCallingUid(), null);
3953 }
3954 if (userHandle != UserHandle.getCallingUserId()) {
3955 if (mContext.checkCallingOrSelfPermission(Manifest.permission
3956 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
3957 && mContext.checkCallingOrSelfPermission(Manifest.permission
3958 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
3959 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
3960 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04003961 }
3962 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003963 verifyIncomingOp(code);
3964 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003965 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003966 }
3967
3968 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08003969 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07003970 synchronized (AppOpsService.this) {
3971 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
3972
3973 if (restrictionState == null) {
3974 try {
3975 restrictionState = new ClientRestrictionState(token);
3976 } catch (RemoteException e) {
3977 return;
3978 }
3979 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003980 }
Svet Ganov442ed572016-08-17 17:29:43 -07003981
3982 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003983 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07003984 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07003985 }
3986
3987 if (restrictionState.isDefault()) {
3988 mOpUserRestrictions.remove(token);
3989 restrictionState.destroy();
3990 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003991 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04003992 }
3993
Svet Ganov3a95f832018-03-23 17:44:30 -07003994 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003995 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003996 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003997 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003998 if (callbacks == null) {
3999 return;
4000 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08004001 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004002 }
4003
Svet Ganov3a95f832018-03-23 17:44:30 -07004004 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04004005 }
4006
4007 @Override
4008 public void removeUser(int userHandle) throws RemoteException {
4009 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07004010 synchronized (AppOpsService.this) {
4011 final int tokenCount = mOpUserRestrictions.size();
4012 for (int i = tokenCount - 1; i >= 0; i--) {
4013 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
4014 opRestrictions.removeUser(userHandle);
4015 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004016 removeUidsForUserLocked(userHandle);
4017 }
4018 }
4019
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004020 @Override
4021 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08004022 if (Binder.getCallingUid() != uid) {
4023 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
4024 != PackageManager.PERMISSION_GRANTED) {
4025 return false;
4026 }
4027 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004028 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004029 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004030 if (resolvedPackageName == null) {
4031 return false;
4032 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004033 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004034 for (int i = mClients.size() - 1; i >= 0; i--) {
4035 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06004036 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
4037 final Op op = client.mStartedOps.get(j);
4038 if (op.op == code && op.uid == uid) return true;
4039 }
4040 }
4041 }
4042 return false;
4043 }
4044
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004045 private void removeUidsForUserLocked(int userHandle) {
4046 for (int i = mUidStates.size() - 1; i >= 0; --i) {
4047 final int uid = mUidStates.keyAt(i);
4048 if (UserHandle.getUserId(uid) == userHandle) {
4049 mUidStates.removeAt(i);
4050 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004051 }
4052 }
4053
Jason Monk62062992014-05-06 09:55:28 -04004054 private void checkSystemUid(String function) {
4055 int uid = Binder.getCallingUid();
4056 if (uid != Process.SYSTEM_UID) {
4057 throw new SecurityException(function + " must by called by the system");
4058 }
4059 }
4060
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004061 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08004062 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004063 return "root";
4064 } else if (uid == Process.SHELL_UID) {
4065 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08004066 } else if (uid == Process.MEDIA_UID) {
4067 return "media";
4068 } else if (uid == Process.AUDIOSERVER_UID) {
4069 return "audioserver";
4070 } else if (uid == Process.CAMERASERVER_UID) {
4071 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00004072 } else if (uid == Process.SYSTEM_UID && packageName == null) {
4073 return "android";
4074 }
4075 return packageName;
4076 }
4077
Svet Ganov82f09bc2018-01-12 22:08:40 -08004078 private static int resolveUid(String packageName) {
4079 if (packageName == null) {
4080 return -1;
4081 }
4082 switch (packageName) {
4083 case "root":
4084 return Process.ROOT_UID;
4085 case "shell":
4086 return Process.SHELL_UID;
4087 case "media":
4088 return Process.MEDIA_UID;
4089 case "audioserver":
4090 return Process.AUDIOSERVER_UID;
4091 case "cameraserver":
4092 return Process.CAMERASERVER_UID;
4093 }
4094 return -1;
4095 }
4096
Svet Ganov2af57082015-07-30 08:44:20 -07004097 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07004098 String[] packageNames = null;
Philip P. Moltmann159d98b2018-12-20 08:30:53 -08004099
4100 // Very early during boot the package manager is not yet or not yet fully started. At this
4101 // time there are no packages yet.
4102 if (AppGlobals.getPackageManager() != null) {
4103 try {
4104 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
4105 } catch (RemoteException e) {
4106 /* ignore - local call */
4107 }
Svet Ganov2af57082015-07-30 08:44:20 -07004108 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07004109 if (packageNames == null) {
4110 return EmptyArray.STRING;
4111 }
4112 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07004113 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004114
4115 private final class ClientRestrictionState implements DeathRecipient {
4116 private final IBinder token;
4117 SparseArray<boolean[]> perUserRestrictions;
4118 SparseArray<String[]> perUserExcludedPackages;
4119
4120 public ClientRestrictionState(IBinder token)
4121 throws RemoteException {
4122 token.linkToDeath(this, 0);
4123 this.token = token;
4124 }
4125
4126 public boolean setRestriction(int code, boolean restricted,
4127 String[] excludedPackages, int userId) {
4128 boolean changed = false;
4129
4130 if (perUserRestrictions == null && restricted) {
4131 perUserRestrictions = new SparseArray<>();
4132 }
4133
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004134 int[] users;
4135 if (userId == UserHandle.USER_ALL) {
4136 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004137
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004138 users = new int[liveUsers.size()];
4139 for (int i = 0; i < liveUsers.size(); i++) {
4140 users[i] = liveUsers.get(i).id;
4141 }
4142 } else {
4143 users = new int[]{userId};
4144 }
4145
4146 if (perUserRestrictions != null) {
4147 int numUsers = users.length;
4148
4149 for (int i = 0; i < numUsers; i++) {
4150 int thisUserId = users[i];
4151
4152 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
4153 if (userRestrictions == null && restricted) {
4154 userRestrictions = new boolean[AppOpsManager._NUM_OP];
4155 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004156 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004157 if (userRestrictions != null && userRestrictions[code] != restricted) {
4158 userRestrictions[code] = restricted;
4159 if (!restricted && isDefault(userRestrictions)) {
4160 perUserRestrictions.remove(thisUserId);
4161 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004162 }
4163 changed = true;
4164 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07004165
4166 if (userRestrictions != null) {
4167 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
4168 if (perUserExcludedPackages == null && !noExcludedPackages) {
4169 perUserExcludedPackages = new SparseArray<>();
4170 }
4171 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
4172 perUserExcludedPackages.get(thisUserId))) {
4173 if (noExcludedPackages) {
4174 perUserExcludedPackages.remove(thisUserId);
4175 if (perUserExcludedPackages.size() <= 0) {
4176 perUserExcludedPackages = null;
4177 }
4178 } else {
4179 perUserExcludedPackages.put(thisUserId, excludedPackages);
4180 }
4181 changed = true;
4182 }
4183 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004184 }
4185 }
4186
4187 return changed;
4188 }
4189
4190 public boolean hasRestriction(int restriction, String packageName, int userId) {
4191 if (perUserRestrictions == null) {
4192 return false;
4193 }
4194 boolean[] restrictions = perUserRestrictions.get(userId);
4195 if (restrictions == null) {
4196 return false;
4197 }
4198 if (!restrictions[restriction]) {
4199 return false;
4200 }
4201 if (perUserExcludedPackages == null) {
4202 return true;
4203 }
4204 String[] perUserExclusions = perUserExcludedPackages.get(userId);
4205 if (perUserExclusions == null) {
4206 return true;
4207 }
4208 return !ArrayUtils.contains(perUserExclusions, packageName);
4209 }
4210
4211 public void removeUser(int userId) {
4212 if (perUserExcludedPackages != null) {
4213 perUserExcludedPackages.remove(userId);
4214 if (perUserExcludedPackages.size() <= 0) {
4215 perUserExcludedPackages = null;
4216 }
4217 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07004218 if (perUserRestrictions != null) {
4219 perUserRestrictions.remove(userId);
4220 if (perUserRestrictions.size() <= 0) {
4221 perUserRestrictions = null;
4222 }
4223 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004224 }
4225
4226 public boolean isDefault() {
4227 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
4228 }
4229
4230 @Override
4231 public void binderDied() {
4232 synchronized (AppOpsService.this) {
4233 mOpUserRestrictions.remove(token);
4234 if (perUserRestrictions == null) {
4235 return;
4236 }
4237 final int userCount = perUserRestrictions.size();
4238 for (int i = 0; i < userCount; i++) {
4239 final boolean[] restrictions = perUserRestrictions.valueAt(i);
4240 final int restrictionCount = restrictions.length;
4241 for (int j = 0; j < restrictionCount; j++) {
4242 if (restrictions[j]) {
4243 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07004244 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004245 }
4246 }
4247 }
4248 destroy();
4249 }
4250 }
4251
4252 public void destroy() {
4253 token.unlinkToDeath(this, 0);
4254 }
4255
4256 private boolean isDefault(boolean[] array) {
4257 if (ArrayUtils.isEmpty(array)) {
4258 return true;
4259 }
4260 for (boolean value : array) {
4261 if (value) {
4262 return false;
4263 }
4264 }
4265 return true;
4266 }
4267 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07004268
4269 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
4270 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
4271 synchronized (AppOpsService.this) {
4272 mProfileOwners = owners;
4273 }
4274 }
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07004275
4276 @Override
Philip P. Moltmann159d98b2018-12-20 08:30:53 -08004277 public void setUidMode(int code, int uid, int mode) {
4278 AppOpsService.this.setUidMode(code, uid, mode);
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07004279 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07004280 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004281}