blob: 13503e60183f4bafa936109ba87cea9c3b542378 [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
Philip P. Moltmanne683f192017-06-23 14:05:04 -070019import android.Manifest;
20import android.app.ActivityManager;
21import android.app.ActivityThread;
22import android.app.AppGlobals;
23import android.app.AppOpsManager;
24import android.content.Context;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.IPackageManager;
27import android.content.pm.PackageManager;
28import android.content.pm.PackageManagerInternal;
29import android.content.pm.UserInfo;
30import android.media.AudioAttributes;
31import android.os.AsyncTask;
32import android.os.Binder;
33import android.os.Bundle;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.Process;
37import android.os.RemoteException;
38import android.os.ResultReceiver;
39import android.os.ServiceManager;
40import android.os.ShellCallback;
41import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070042import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070043import android.os.UserHandle;
44import android.os.UserManager;
45import android.os.storage.StorageManagerInternal;
46import android.util.ArrayMap;
47import android.util.ArraySet;
48import android.util.AtomicFile;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070049import android.util.Slog;
50import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -070051import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070052import android.util.SparseIntArray;
53import android.util.TimeUtils;
54import android.util.Xml;
55
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -070056import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080057import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070058import com.android.internal.app.IAppOpsCallback;
59import com.android.internal.app.IAppOpsService;
60import com.android.internal.os.Zygote;
61import com.android.internal.util.ArrayUtils;
62import com.android.internal.util.DumpUtils;
63import com.android.internal.util.FastXmlSerializer;
64import com.android.internal.util.Preconditions;
65import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -080066import com.android.internal.util.function.pooled.PooledLambda;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -050067
Philip P. Moltmanne683f192017-06-23 14:05:04 -070068import libcore.util.EmptyArray;
69
70import org.xmlpull.v1.XmlPullParser;
71import org.xmlpull.v1.XmlPullParserException;
72import org.xmlpull.v1.XmlSerializer;
73
Dianne Hackborna06de0f2012-12-11 16:34:47 -080074import java.io.File;
75import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -080076import java.io.FileInputStream;
77import java.io.FileNotFoundException;
78import java.io.FileOutputStream;
79import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080080import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010081import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070082import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -080083import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -070084import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -070085import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070086import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080087import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -080088import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -080089import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -070090import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080091
Dianne Hackborncd1f30b2018-04-23 17:38:09 -070092import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
93import static android.app.AppOpsManager.UID_STATE_CACHED;
94import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
95import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
96import static android.app.AppOpsManager._NUM_UID_STATE;
97import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
98import static android.app.AppOpsManager.UID_STATE_TOP;
99
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800100public class AppOpsService extends IAppOpsService.Stub {
101 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800102 static final boolean DEBUG = false;
103
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700104 private static final int NO_VERSION = -1;
105 /** Increment by one every time and add the corresponding upgrade logic in
106 * {@link #upgradeLocked(int)} below. The first version was 1 */
107 private static final int CURRENT_VERSION = 1;
108
Dianne Hackborn35654b62013-01-14 17:38:02 -0800109 // Write at most every 30 minutes.
110 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800111
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700112 // How long we want for a drop in uid state to settle before applying it.
113 static final long STATE_SETTLE_TIME = 10*1000;
114
Svet Ganov3a95f832018-03-23 17:44:30 -0700115 // Constant meaning that any UID should be matched when dispatching callbacks
116 private static final int UID_ANY = -2;
117
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700118 // Map from process states to the uid states we track.
119 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
120 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
121 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
122 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
123 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
124 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
125 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
126 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
127 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
128 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
129 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
130 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
131 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
132 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
133 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
134 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
135 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
136 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
137 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
138 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
139 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
140 };
141
142 static final String[] UID_STATE_NAMES = new String[] {
143 "pers ", // UID_STATE_PERSISTENT
144 "top ", // UID_STATE_TOP
145 "fgsvc", // UID_STATE_FOREGROUND_SERVICE
146 "fg ", // UID_STATE_FOREGROUND
147 "bg ", // UID_STATE_BACKGROUND
148 "cch ", // UID_STATE_CACHED
149 };
150
151 static final String[] UID_STATE_TIME_ATTRS = new String[] {
152 "tp", // UID_STATE_PERSISTENT
153 "tt", // UID_STATE_TOP
154 "tfs", // UID_STATE_FOREGROUND_SERVICE
155 "tf", // UID_STATE_FOREGROUND
156 "tb", // UID_STATE_BACKGROUND
157 "tc", // UID_STATE_CACHED
158 };
159
160 static final String[] UID_STATE_REJECT_ATTRS = new String[] {
161 "rp", // UID_STATE_PERSISTENT
162 "rt", // UID_STATE_TOP
163 "rfs", // UID_STATE_FOREGROUND_SERVICE
164 "rf", // UID_STATE_FOREGROUND
165 "rb", // UID_STATE_BACKGROUND
166 "rc", // UID_STATE_CACHED
167 };
168
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800169 Context mContext;
170 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800171 final Handler mHandler;
172
173 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800174 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800175 final Runnable mWriteRunner = new Runnable() {
176 public void run() {
177 synchronized (AppOpsService.this) {
178 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800179 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800180 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
181 @Override protected Void doInBackground(Void... params) {
182 writeState();
183 return null;
184 }
185 };
186 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
187 }
188 }
189 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800190
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700191 @VisibleForTesting
192 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800193
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700194 long mLastUptime;
195
Ruben Brunk29931bc2016-03-11 00:24:26 -0800196 /*
197 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800198 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700199 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400200
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700201 @VisibleForTesting
202 static final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700203 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700204
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700205 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700206 public int pendingState = UID_STATE_CACHED;
207 public long pendingStateCommitTime;
208
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700209 public int startNesting;
Svet Ganov2af57082015-07-30 08:44:20 -0700210 public ArrayMap<String, Ops> pkgOps;
211 public SparseIntArray opModes;
212
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700213 public SparseBooleanArray foregroundOps;
214
Svet Ganov2af57082015-07-30 08:44:20 -0700215 public UidState(int uid) {
216 this.uid = uid;
217 }
218
219 public void clear() {
220 pkgOps = null;
221 opModes = null;
222 }
223
224 public boolean isDefault() {
225 return (pkgOps == null || pkgOps.isEmpty())
226 && (opModes == null || opModes.size() <= 0);
227 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700228
229 int evalMode(int mode) {
230 if (mode == AppOpsManager.MODE_FOREGROUND) {
231 return state <= UID_STATE_FOREGROUND_SERVICE
232 ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
233 }
234 return mode;
235 }
236
237 public void evalForegroundOps() {
238 SparseBooleanArray which = null;
239 if (pkgOps != null) {
240 for (int i = pkgOps.size() - 1; i >= 0; i--) {
241 Ops ops = pkgOps.valueAt(i);
242 for (int j = ops.size() - 1; j >= 0; j--) {
243 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
244 if (which == null) {
245 which = new SparseBooleanArray();
246 }
247 which.put(ops.keyAt(j), true);
248 }
249 }
250 }
251 }
252 foregroundOps = which;
253 }
Svet Ganov2af57082015-07-30 08:44:20 -0700254 }
255
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700256 final static class Ops extends SparseArray<Op> {
257 final String packageName;
258 final UidState uidState;
259 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800260
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700261 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800262 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700263 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400264 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800265 }
266 }
267
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700268 final static class Op {
269 final UidState uidState;
270 final int uid;
271 final String packageName;
272 final int op;
273 int proxyUid = -1;
274 String proxyPackageName;
275 int mode;
276 int duration;
277 long time[] = new long[_NUM_UID_STATE];
278 long rejectTime[] = new long[_NUM_UID_STATE];
279 int startNesting;
280 long startRealtime;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800281
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700282 Op(UidState _uidState, String _packageName, int _op) {
283 uidState = _uidState;
284 uid = _uidState.uid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700285 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800286 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700287 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800288 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700289
290 boolean hasAnyTime() {
291 for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
292 if (time[i] != 0) {
293 return true;
294 }
295 if (rejectTime[i] != 0) {
296 return true;
297 }
298 }
299 return false;
300 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700301
302 int getMode() {
303 return uidState.evalMode(mode);
304 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800305 }
306
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800307 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
308 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
309 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
310 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Dianne Hackborn68d76552017-02-27 15:32:03 -0800311 final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800312
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700313 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800314 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700315 final int mWatchingUid;
316 final int mCallingUid;
317 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800318
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700319 ModeCallback(IAppOpsCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700320 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800321 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700322 mWatchingUid = watchingUid;
323 mCallingUid = callingUid;
324 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800325 try {
326 mCallback.asBinder().linkToDeath(this, 0);
327 } catch (RemoteException e) {
328 }
329 }
330
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700331 @Override
332 public String toString() {
333 StringBuilder sb = new StringBuilder(128);
334 sb.append("ModeCallback{");
335 sb.append(Integer.toHexString(System.identityHashCode(this)));
336 sb.append(" watchinguid=");
337 UserHandle.formatUid(sb, mWatchingUid);
338 sb.append(" from uid=");
339 UserHandle.formatUid(sb, mCallingUid);
340 sb.append(" pid=");
341 sb.append(mCallingPid);
342 sb.append('}');
343 return sb.toString();
344 }
345
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700346 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800347 mCallback.asBinder().unlinkToDeath(this, 0);
348 }
349
350 @Override
351 public void binderDied() {
352 stopWatchingMode(mCallback);
353 }
354 }
355
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700356 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800357 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700358 final int mWatchingUid;
359 final int mCallingUid;
360 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800361
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700362 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700363 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800364 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700365 mWatchingUid = watchingUid;
366 mCallingUid = callingUid;
367 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800368 try {
369 mCallback.asBinder().linkToDeath(this, 0);
370 } catch (RemoteException e) {
371 }
372 }
373
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700374 @Override
375 public String toString() {
376 StringBuilder sb = new StringBuilder(128);
377 sb.append("ActiveCallback{");
378 sb.append(Integer.toHexString(System.identityHashCode(this)));
379 sb.append(" watchinguid=");
380 UserHandle.formatUid(sb, mWatchingUid);
381 sb.append(" from uid=");
382 UserHandle.formatUid(sb, mCallingUid);
383 sb.append(" pid=");
384 sb.append(mCallingPid);
385 sb.append('}');
386 return sb.toString();
387 }
388
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700389 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800390 mCallback.asBinder().unlinkToDeath(this, 0);
391 }
392
393 @Override
394 public void binderDied() {
395 stopWatchingActive(mCallback);
396 }
397 }
398
Svet Ganova7a0db62018-02-27 20:08:01 -0800399 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700400
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700401 final class ClientState extends Binder implements DeathRecipient {
Svet Ganovf7b47252018-02-26 11:11:27 -0800402 final ArrayList<Op> mStartedOps = new ArrayList<>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700403 final IBinder mAppToken;
404 final int mPid;
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700405
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700406 ClientState(IBinder appToken) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700407 mAppToken = appToken;
408 mPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -0800409 // Watch only for remote processes dying
410 if (!(appToken instanceof Binder)) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700411 try {
412 mAppToken.linkToDeath(this, 0);
413 } catch (RemoteException e) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800414 /* do nothing */
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700415 }
416 }
417 }
418
419 @Override
420 public String toString() {
421 return "ClientState{" +
422 "mAppToken=" + mAppToken +
Svet Ganovf7b47252018-02-26 11:11:27 -0800423 ", " + "pid=" + mPid +
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700424 '}';
425 }
426
427 @Override
428 public void binderDied() {
429 synchronized (AppOpsService.this) {
430 for (int i=mStartedOps.size()-1; i>=0; i--) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800431 finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700432 }
433 mClients.remove(mAppToken);
434 }
435 }
436 }
437
Jeff Brown6f357d32014-01-15 20:40:55 -0800438 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600439 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800440 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -0800441 mHandler = handler;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800442 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800443 }
David Braunf5d83192013-09-16 13:43:51 -0700444
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800445 public void publish(Context context) {
446 mContext = context;
447 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
448 }
449
Dianne Hackborn514074f2013-02-11 10:52:46 -0800450 public void systemReady() {
451 synchronized (this) {
452 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700453 for (int i = mUidStates.size() - 1; i >= 0; i--) {
454 UidState uidState = mUidStates.valueAt(i);
455
456 String[] packageNames = getPackagesForUid(uidState.uid);
457 if (ArrayUtils.isEmpty(packageNames)) {
458 uidState.clear();
459 mUidStates.removeAt(i);
460 changed = true;
461 continue;
462 }
463
464 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
465 if (pkgs == null) {
466 continue;
467 }
468
Dianne Hackborn514074f2013-02-11 10:52:46 -0800469 Iterator<Ops> it = pkgs.values().iterator();
470 while (it.hasNext()) {
471 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700472 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800473 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700474 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
475 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700476 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700477 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800478 }
Svet Ganov2af57082015-07-30 08:44:20 -0700479 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800480 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700481 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800482 it.remove();
483 changed = true;
484 }
485 }
Svet Ganov2af57082015-07-30 08:44:20 -0700486
487 if (uidState.isDefault()) {
488 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800489 }
490 }
491 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800492 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800493 }
494 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700495
Suprabh Shuklaaef25132017-01-23 18:09:03 -0800496 PackageManagerInternal packageManagerInternal = LocalServices.getService(
497 PackageManagerInternal.class);
498 packageManagerInternal.setExternalSourcesPolicy(
499 new PackageManagerInternal.ExternalSourcesPolicy() {
500 @Override
501 public int getPackageTrustedToInstallApps(String packageName, int uid) {
502 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
503 uid, packageName);
504 switch (appOpMode) {
505 case AppOpsManager.MODE_ALLOWED:
506 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
507 case AppOpsManager.MODE_ERRORED:
508 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
509 default:
510 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
511 }
512 }
513 });
514
Sudheer Shanka2250d562016-11-07 15:41:02 -0800515 StorageManagerInternal storageManagerInternal = LocalServices.getService(
516 StorageManagerInternal.class);
517 storageManagerInternal.addExternalStoragePolicy(
518 new StorageManagerInternal.ExternalStorageMountPolicy() {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700519 @Override
520 public int getMountMode(int uid, String packageName) {
521 if (Process.isIsolated(uid)) {
522 return Zygote.MOUNT_EXTERNAL_NONE;
523 }
524 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
525 packageName) != AppOpsManager.MODE_ALLOWED) {
526 return Zygote.MOUNT_EXTERNAL_NONE;
527 }
528 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
529 packageName) != AppOpsManager.MODE_ALLOWED) {
530 return Zygote.MOUNT_EXTERNAL_READ;
531 }
532 return Zygote.MOUNT_EXTERNAL_WRITE;
533 }
534
535 @Override
536 public boolean hasExternalStorage(int uid, String packageName) {
537 final int mountMode = getMountMode(uid, packageName);
538 return mountMode == Zygote.MOUNT_EXTERNAL_READ
539 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
540 }
541 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800542 }
543
544 public void packageRemoved(int uid, String packageName) {
545 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700546 UidState uidState = mUidStates.get(uid);
547 if (uidState == null) {
548 return;
549 }
550
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800551 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700552
553 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800554 if (uidState.pkgOps != null) {
555 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700556 }
557
558 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800559 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -0700560 && getPackagesForUid(uid).length <= 0) {
561 mUidStates.remove(uid);
562 }
563
Svet Ganova7a0db62018-02-27 20:08:01 -0800564 // Finish ops other packages started on behalf of the package.
565 final int clientCount = mClients.size();
566 for (int i = 0; i < clientCount; i++) {
567 final ClientState client = mClients.valueAt(i);
568 if (client.mStartedOps == null) {
569 continue;
570 }
571 final int opCount = client.mStartedOps.size();
572 for (int j = opCount - 1; j >= 0; j--) {
573 final Op op = client.mStartedOps.get(j);
574 if (uid == op.uid && packageName.equals(op.packageName)) {
575 finishOperationLocked(op, /*finishNested*/ true);
576 client.mStartedOps.remove(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700577 if (op.startNesting <= 0) {
Svet Ganova7a0db62018-02-27 20:08:01 -0800578 scheduleOpActiveChangedIfNeededLocked(op.op,
579 uid, packageName, false);
580 }
581 }
582 }
583 }
584
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800585 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700586 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800587
588 final int opCount = ops.size();
589 for (int i = 0; i < opCount; i++) {
590 final Op op = ops.valueAt(i);
591 if (op.duration == -1) {
592 scheduleOpActiveChangedIfNeededLocked(
593 op.op, op.uid, op.packageName, false);
594 }
595 }
Dianne Hackborn514074f2013-02-11 10:52:46 -0800596 }
597 }
598 }
599
600 public void uidRemoved(int uid) {
601 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700602 if (mUidStates.indexOfKey(uid) >= 0) {
603 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800604 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800605 }
606 }
607 }
608
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700609 public void updateUidProcState(int uid, int procState) {
610 synchronized (this) {
611 final UidState uidState = getUidStateLocked(uid, true);
612 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700613 if (uidState != null && uidState.pendingState != newState) {
614 if (newState < uidState.state) {
615 // We are moving to a more important state, always do it immediately.
616 uidState.state = newState;
617 uidState.pendingStateCommitTime = 0;
618 } else if (uidState.pendingStateCommitTime == 0) {
619 // We are moving to a less important state for the first time,
620 // delay the application for a bit.
621 uidState.pendingStateCommitTime = SystemClock.uptimeMillis() + STATE_SETTLE_TIME;
622 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700623 if (uidState.startNesting != 0) {
624 // There is some actively running operation... need to find it
625 // and appropriately update its state.
626 final long now = System.currentTimeMillis();
627 for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
628 final Ops ops = uidState.pkgOps.valueAt(i);
629 for (int j = ops.size() - 1; j >= 0; j--) {
630 final Op op = ops.valueAt(j);
631 if (op.startNesting > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700632 op.time[uidState.pendingState] = now;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700633 op.time[newState] = now;
634 }
635 }
636 }
637 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700638 uidState.pendingState = newState;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700639 }
640 }
641 }
642
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800643 public void shutdown() {
644 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800645 boolean doWrite = false;
646 synchronized (this) {
647 if (mWriteScheduled) {
648 mWriteScheduled = false;
649 doWrite = true;
650 }
651 }
652 if (doWrite) {
653 writeState();
654 }
655 }
656
Dianne Hackborn72e39832013-01-18 18:36:09 -0800657 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
658 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700659 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800660 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700661 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800662 for (int j=0; j<pkgOps.size(); j++) {
663 Op curOp = pkgOps.valueAt(j);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700664 long duration = curOp.duration == -1
665 ? (elapsedNow - curOp.startRealtime)
666 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800667 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700668 curOp.rejectTime, (int) duration, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700669 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800670 }
671 } else {
672 for (int j=0; j<ops.length; j++) {
673 Op curOp = pkgOps.get(ops[j]);
674 if (curOp != null) {
675 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700676 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -0800677 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700678 long duration = curOp.duration == -1
679 ? (elapsedNow - curOp.startRealtime)
680 : curOp.duration;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800681 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700682 curOp.rejectTime, (int) duration, curOp.proxyUid,
Svet Ganov99b60432015-06-27 13:15:22 -0700683 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800684 }
685 }
686 }
687 return resOps;
688 }
689
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700690 private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
691 ArrayList<AppOpsManager.OpEntry> resOps = null;
692 if (ops == null) {
693 resOps = new ArrayList<>();
694 for (int j=0; j<uidOps.size(); j++) {
695 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
696 0, 0, 0, -1, null));
697 }
698 } else {
699 for (int j=0; j<ops.length; j++) {
700 int index = uidOps.indexOfKey(ops[j]);
701 if (index >= 0) {
702 if (resOps == null) {
703 resOps = new ArrayList<>();
704 }
705 resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
706 0, 0, 0, -1, null));
707 }
708 }
709 }
710 return resOps;
711 }
712
Dianne Hackborn35654b62013-01-14 17:38:02 -0800713 @Override
714 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
715 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
716 Binder.getCallingPid(), Binder.getCallingUid(), null);
717 ArrayList<AppOpsManager.PackageOps> res = null;
718 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700719 final int uidStateCount = mUidStates.size();
720 for (int i = 0; i < uidStateCount; i++) {
721 UidState uidState = mUidStates.valueAt(i);
722 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
723 continue;
724 }
725 ArrayMap<String, Ops> packages = uidState.pkgOps;
726 final int packageCount = packages.size();
727 for (int j = 0; j < packageCount; j++) {
728 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800729 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800730 if (resOps != null) {
731 if (res == null) {
732 res = new ArrayList<AppOpsManager.PackageOps>();
733 }
734 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700735 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800736 res.add(resPackage);
737 }
738 }
739 }
740 }
741 return res;
742 }
743
744 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800745 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
746 int[] ops) {
747 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
748 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000749 String resolvedPackageName = resolvePackageName(uid, packageName);
750 if (resolvedPackageName == null) {
751 return Collections.emptyList();
752 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800753 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700754 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
755 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800756 if (pkgOps == null) {
757 return null;
758 }
759 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
760 if (resOps == null) {
761 return null;
762 }
763 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
764 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700765 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800766 res.add(resPackage);
767 return res;
768 }
769 }
770
Dianne Hackbornc7214a32017-04-11 13:32:47 -0700771 @Override
772 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
773 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
774 Binder.getCallingPid(), Binder.getCallingUid(), null);
775 synchronized (this) {
776 UidState uidState = getUidStateLocked(uid, false);
777 if (uidState == null) {
778 return null;
779 }
780 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
781 if (resOps == null) {
782 return null;
783 }
784 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
785 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
786 null, uidState.uid, resOps);
787 res.add(resPackage);
788 return res;
789 }
790 }
791
Dianne Hackborn607b4142013-08-02 18:10:10 -0700792 private void pruneOp(Op op, int uid, String packageName) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700793 if (!op.hasAnyTime()) {
Yohei Yukawaa965d652017-10-12 15:02:26 -0700794 Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
795 false /* uidMismatchExpected */);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700796 if (ops != null) {
797 ops.remove(op.op);
798 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700799 UidState uidState = ops.uidState;
800 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700801 if (pkgOps != null) {
802 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700803 if (pkgOps.isEmpty()) {
804 uidState.pkgOps = null;
805 }
806 if (uidState.isDefault()) {
807 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700808 }
809 }
810 }
811 }
812 }
813 }
814
Dianne Hackborn72e39832013-01-18 18:36:09 -0800815 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700816 public void setUidMode(int code, int uid, int mode) {
817 if (Binder.getCallingPid() != Process.myPid()) {
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -0800818 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Svet Ganov2af57082015-07-30 08:44:20 -0700819 Binder.getCallingPid(), Binder.getCallingUid(), null);
820 }
821 verifyIncomingOp(code);
822 code = AppOpsManager.opToSwitch(code);
823
824 synchronized (this) {
825 final int defaultMode = AppOpsManager.opToDefaultMode(code);
826
827 UidState uidState = getUidStateLocked(uid, false);
828 if (uidState == null) {
829 if (mode == defaultMode) {
830 return;
831 }
832 uidState = new UidState(uid);
833 uidState.opModes = new SparseIntArray();
834 uidState.opModes.put(code, mode);
835 mUidStates.put(uid, uidState);
836 scheduleWriteLocked();
837 } else if (uidState.opModes == null) {
838 if (mode != defaultMode) {
839 uidState.opModes = new SparseIntArray();
840 uidState.opModes.put(code, mode);
841 scheduleWriteLocked();
842 }
843 } else {
844 if (uidState.opModes.get(code) == mode) {
845 return;
846 }
847 if (mode == defaultMode) {
848 uidState.opModes.delete(code);
849 if (uidState.opModes.size() <= 0) {
850 uidState.opModes = null;
851 }
852 } else {
853 uidState.opModes.put(code, mode);
854 }
855 scheduleWriteLocked();
856 }
857 }
858
Svetoslav215b44a2015-08-04 19:03:40 -0700859 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800860 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -0700861
riddle_hsu40b300f2015-11-23 13:22:03 +0800862 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800863 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -0700864 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700865 final int callbackCount = callbacks.size();
866 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800867 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800868 ArraySet<String> changedPackages = new ArraySet<>();
869 Collections.addAll(changedPackages, uidPackageNames);
870 callbackSpecs = new ArrayMap<>();
871 callbackSpecs.put(callback, changedPackages);
872 }
873 }
874
875 for (String uidPackageName : uidPackageNames) {
876 callbacks = mPackageModeWatchers.get(uidPackageName);
877 if (callbacks != null) {
878 if (callbackSpecs == null) {
879 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -0700880 }
riddle_hsu40b300f2015-11-23 13:22:03 +0800881 final int callbackCount = callbacks.size();
882 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800883 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800884 ArraySet<String> changedPackages = callbackSpecs.get(callback);
885 if (changedPackages == null) {
886 changedPackages = new ArraySet<>();
887 callbackSpecs.put(callback, changedPackages);
888 }
889 changedPackages.add(uidPackageName);
890 }
Svet Ganov2af57082015-07-30 08:44:20 -0700891 }
892 }
893 }
894
895 if (callbackSpecs == null) {
896 return;
897 }
898
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800899 for (int i = 0; i < callbackSpecs.size(); i++) {
900 final ModeCallback callback = callbackSpecs.keyAt(i);
901 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
902 if (reportedPackageNames == null) {
903 mHandler.sendMessage(PooledLambda.obtainMessage(
904 AppOpsService::notifyOpChanged,
905 this, callback, code, uid, (String) null));
906
907 } else {
908 final int reportedPackageCount = reportedPackageNames.size();
909 for (int j = 0; j < reportedPackageCount; j++) {
910 final String reportedPackageName = reportedPackageNames.valueAt(j);
911 mHandler.sendMessage(PooledLambda.obtainMessage(
912 AppOpsService::notifyOpChanged,
913 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -0700914 }
915 }
Svet Ganov2af57082015-07-30 08:44:20 -0700916 }
917 }
918
919 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800920 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornb64afe12014-07-22 16:29:04 -0700921 if (Binder.getCallingPid() != Process.myPid()) {
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -0800922 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackbornb64afe12014-07-22 16:29:04 -0700923 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborn133b9df2014-07-01 13:06:10 -0700924 }
Dianne Hackborn961321f2013-02-05 17:22:41 -0800925 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800926 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800927 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800928 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700929 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800930 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800931 if (op != null) {
932 if (op.mode != mode) {
933 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700934 if (uidState != null) {
935 uidState.evalForegroundOps();
936 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800937 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800938 if (cbs != null) {
939 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800940 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800941 }
942 repCbs.addAll(cbs);
943 }
944 cbs = mPackageModeWatchers.get(packageName);
945 if (cbs != null) {
946 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800947 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800948 }
949 repCbs.addAll(cbs);
950 }
David Braunf5d83192013-09-16 13:43:51 -0700951 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800952 // If going into the default mode, prune this op
953 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -0700954 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800955 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800956 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800957 }
958 }
959 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800960 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800961 mHandler.sendMessage(PooledLambda.obtainMessage(
962 AppOpsService::notifyOpChanged,
963 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -0800964 }
965 }
966
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800967 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
968 int uid, String packageName) {
969 for (int i = 0; i < callbacks.size(); i++) {
970 final ModeCallback callback = callbacks.valueAt(i);
971 notifyOpChanged(callback, code, uid, packageName);
972 }
973 }
974
975 private void notifyOpChanged(ModeCallback callback, int code,
976 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -0700977 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800978 return;
979 }
980 // There are components watching for mode changes such as window manager
981 // and location manager which are in our process. The callbacks in these
982 // components may require permissions our remote caller does not have.
983 final long identity = Binder.clearCallingIdentity();
984 try {
985 callback.mCallback.opChanged(code, uid, packageName);
986 } catch (RemoteException e) {
987 /* ignore */
988 } finally {
989 Binder.restoreCallingIdentity(identity);
990 }
991 }
992
993 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
994 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
995 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700996 if (cbs == null) {
997 return callbacks;
998 }
999 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001000 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001001 }
Svet Ganov2af57082015-07-30 08:44:20 -07001002 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08001003 final int N = cbs.size();
1004 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001005 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001006 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001007 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001008 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001009 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07001010 } else {
1011 final int reportCount = reports.size();
1012 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001013 ChangeRec report = reports.get(j);
1014 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001015 duplicate = true;
1016 break;
1017 }
1018 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001019 }
Svet Ganov2af57082015-07-30 08:44:20 -07001020 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001021 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07001022 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001023 }
1024 return callbacks;
1025 }
1026
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001027 static final class ChangeRec {
1028 final int op;
1029 final int uid;
1030 final String pkg;
1031
1032 ChangeRec(int _op, int _uid, String _pkg) {
1033 op = _op;
1034 uid = _uid;
1035 pkg = _pkg;
1036 }
1037 }
1038
Dianne Hackborn607b4142013-08-02 18:10:10 -07001039 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001040 public void resetAllModes(int reqUserId, String reqPackageName) {
1041 final int callingPid = Binder.getCallingPid();
1042 final int callingUid = Binder.getCallingUid();
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08001043 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001044 callingPid, callingUid, null);
1045 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
1046 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07001047
1048 int reqUid = -1;
1049 if (reqPackageName != null) {
1050 try {
1051 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07001052 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07001053 } catch (RemoteException e) {
1054 /* ignore - local call */
1055 }
1056 }
1057
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001058 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001059 synchronized (this) {
1060 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07001061 for (int i = mUidStates.size() - 1; i >= 0; i--) {
1062 UidState uidState = mUidStates.valueAt(i);
1063
1064 SparseIntArray opModes = uidState.opModes;
1065 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
1066 final int uidOpCount = opModes.size();
1067 for (int j = uidOpCount - 1; j >= 0; j--) {
1068 final int code = opModes.keyAt(j);
1069 if (AppOpsManager.opAllowsReset(code)) {
1070 opModes.removeAt(j);
1071 if (opModes.size() <= 0) {
1072 uidState.opModes = null;
1073 }
1074 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001075 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001076 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001077 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07001078 mPackageModeWatchers.get(packageName));
1079 }
1080 }
1081 }
1082 }
1083
1084 if (uidState.pkgOps == null) {
1085 continue;
1086 }
1087
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001088 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07001089 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01001090 // Skip any ops for a different user
1091 continue;
1092 }
Svet Ganov2af57082015-07-30 08:44:20 -07001093
1094 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001095 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001096 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001097 while (it.hasNext()) {
1098 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001099 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001100 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
1101 // Skip any ops for a different package
1102 continue;
1103 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001104 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001105 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07001106 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07001107 if (AppOpsManager.opAllowsReset(curOp.op)
1108 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07001109 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001110 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001111 uidChanged = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001112 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001113 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001114 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07001115 mPackageModeWatchers.get(packageName));
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001116 if (!curOp.hasAnyTime()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001117 pkgOps.removeAt(j);
1118 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001119 }
1120 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07001121 if (pkgOps.size() == 0) {
1122 it.remove();
1123 }
1124 }
Svet Ganov2af57082015-07-30 08:44:20 -07001125 if (uidState.isDefault()) {
1126 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001127 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001128 if (uidChanged) {
1129 uidState.evalForegroundOps();
1130 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07001131 }
Svet Ganov2af57082015-07-30 08:44:20 -07001132
Dianne Hackborn607b4142013-08-02 18:10:10 -07001133 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001134 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001135 }
1136 }
1137 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001138 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
1139 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001140 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07001141 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001142 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001143 mHandler.sendMessage(PooledLambda.obtainMessage(
1144 AppOpsService::notifyOpChanged,
1145 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07001146 }
1147 }
1148 }
1149 }
1150
Dianne Hackbornc2293022013-02-06 23:14:49 -08001151 @Override
1152 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001153 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001154 final int callingUid = Binder.getCallingUid();
1155 final int callingPid = Binder.getCallingPid();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001156 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1157 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001158 watchedUid = callingUid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001159 }
1160 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
1161 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001162 if (callback == null) {
1163 return;
1164 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001165 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001166 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001167 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001168 if (cb == null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001169 cb = new ModeCallback(callback, watchedUid, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001170 mModeWatchers.put(callback.asBinder(), cb);
1171 }
1172 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001173 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001174 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001175 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001176 mOpModeWatchers.put(op, cbs);
1177 }
1178 cbs.add(cb);
1179 }
1180 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001181 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001182 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08001183 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001184 mPackageModeWatchers.put(packageName, cbs);
1185 }
1186 cbs.add(cb);
1187 }
1188 }
1189 }
1190
1191 @Override
1192 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08001193 if (callback == null) {
1194 return;
1195 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08001196 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001197 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08001198 if (cb != null) {
1199 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001200 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001201 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001202 cbs.remove(cb);
1203 if (cbs.size() <= 0) {
1204 mOpModeWatchers.removeAt(i);
1205 }
1206 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001207 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001208 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001209 cbs.remove(cb);
1210 if (cbs.size() <= 0) {
1211 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08001212 }
1213 }
1214 }
1215 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001216 }
1217
1218 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001219 public IBinder getToken(IBinder clientToken) {
1220 synchronized (this) {
1221 ClientState cs = mClients.get(clientToken);
1222 if (cs == null) {
1223 cs = new ClientState(clientToken);
1224 mClients.put(clientToken, cs);
1225 }
1226 return cs;
1227 }
1228 }
1229
1230 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08001231 public int checkOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001232 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001233 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001234 String resolvedPackageName = resolvePackageName(uid, packageName);
1235 if (resolvedPackageName == null) {
1236 return AppOpsManager.MODE_IGNORED;
1237 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001238 synchronized (this) {
Svet Ganov442ed572016-08-17 17:29:43 -07001239 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001240 return AppOpsManager.MODE_IGNORED;
1241 }
Svet Ganov2af57082015-07-30 08:44:20 -07001242 code = AppOpsManager.opToSwitch(code);
1243 UidState uidState = getUidStateLocked(uid, false);
Svet Ganovee438d42017-01-19 18:04:38 -08001244 if (uidState != null && uidState.opModes != null
1245 && uidState.opModes.indexOfKey(code) >= 0) {
1246 return uidState.opModes.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001247 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001248 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001249 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07001250 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001251 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001252 return op.mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001253 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001254 }
1255
1256 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001257 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00001258 boolean suspended;
1259 try {
1260 suspended = isPackageSuspendedForUser(packageName, uid);
1261 } catch (IllegalArgumentException ex) {
1262 // Package not found.
1263 suspended = false;
1264 }
1265
1266 if (suspended) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001267 Slog.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001268 return AppOpsManager.MODE_IGNORED;
1269 }
1270
John Spurlock1af30c72014-03-10 08:33:35 -04001271 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001272 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -04001273 if (mode != AppOpsManager.MODE_ALLOWED) {
1274 return mode;
1275 }
1276 }
1277 return checkOperation(code, uid, packageName);
1278 }
1279
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001280 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001281 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001282 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
1283 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001284 } catch (RemoteException re) {
1285 throw new SecurityException("Could not talk to package manager service");
1286 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +00001287 }
1288
John Spurlock7b414672014-07-18 13:02:39 -04001289 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
1290 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1291 if (usageRestrictions != null) {
1292 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001293 if (r != null && !r.exceptionPackages.contains(packageName)) {
1294 return r.mode;
1295 }
1296 }
1297 return AppOpsManager.MODE_ALLOWED;
1298 }
1299
1300 @Override
John Spurlock7b414672014-07-18 13:02:39 -04001301 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04001302 String[] exceptionPackages) {
1303 verifyIncomingUid(uid);
1304 verifyIncomingOp(code);
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08001305 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1306 Binder.getCallingPid(), Binder.getCallingUid(), null);
John Spurlock1af30c72014-03-10 08:33:35 -04001307 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -04001308 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
1309 if (usageRestrictions == null) {
1310 usageRestrictions = new SparseArray<Restriction>();
1311 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -04001312 }
John Spurlock7b414672014-07-18 13:02:39 -04001313 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -04001314 if (mode != AppOpsManager.MODE_ALLOWED) {
1315 final Restriction r = new Restriction();
1316 r.mode = mode;
1317 if (exceptionPackages != null) {
1318 final int N = exceptionPackages.length;
1319 r.exceptionPackages = new ArraySet<String>(N);
1320 for (int i = 0; i < N; i++) {
1321 final String pkg = exceptionPackages[i];
1322 if (pkg != null) {
1323 r.exceptionPackages.add(pkg.trim());
1324 }
1325 }
1326 }
John Spurlock7b414672014-07-18 13:02:39 -04001327 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -04001328 }
1329 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001330
1331 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07001332 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04001333 }
1334
1335 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001336 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001337 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001338 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001339 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1340 true /* uidMismatchExpected */);
1341 if (ops != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001342 return AppOpsManager.MODE_ALLOWED;
1343 } else {
1344 return AppOpsManager.MODE_ERRORED;
1345 }
1346 }
1347 }
1348
1349 @Override
Svet Ganov99b60432015-06-27 13:15:22 -07001350 public int noteProxyOperation(int code, String proxyPackageName,
1351 int proxiedUid, String proxiedPackageName) {
1352 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001353 final int proxyUid = Binder.getCallingUid();
1354 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
1355 if (resolveProxyPackageName == null) {
1356 return AppOpsManager.MODE_IGNORED;
1357 }
1358 final int proxyMode = noteOperationUnchecked(code, proxyUid,
1359 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001360 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
1361 return proxyMode;
1362 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001363 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1364 if (resolveProxiedPackageName == null) {
1365 return AppOpsManager.MODE_IGNORED;
1366 }
1367 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1368 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001369 }
1370
1371 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001372 public int noteOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001373 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001374 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001375 String resolvedPackageName = resolvePackageName(uid, packageName);
1376 if (resolvedPackageName == null) {
1377 return AppOpsManager.MODE_IGNORED;
1378 }
1379 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001380 }
1381
1382 private int noteOperationUnchecked(int code, int uid, String packageName,
1383 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001384 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001385 final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001386 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001387 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001388 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001389 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001390 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001391 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001392 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001393 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001394 return AppOpsManager.MODE_IGNORED;
1395 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001396 final UidState uidState = ops.uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001397 if (op.duration == -1) {
1398 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001399 + " code " + code + " time=" + op.time[uidState.state]
1400 + " duration=" + op.duration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001401 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001402 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001403 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001404 // If there is a non-default per UID policy (we set UID op mode only if
1405 // non-default) it takes over, otherwise use the per package policy.
1406 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001407 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07001408 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001409 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001410 + switchCode + " (" + code + ") uid " + uid + " package "
1411 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001412 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001413 return uidMode;
1414 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001415 } else {
1416 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001417 final int mode = switchOp.getMode();
1418 if (mode != AppOpsManager.MODE_ALLOWED) {
1419 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001420 + switchCode + " (" + code + ") uid " + uid + " package "
1421 + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001422 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001423 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001424 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001425 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001426 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001427 + " package " + packageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001428 op.time[uidState.state] = System.currentTimeMillis();
1429 op.rejectTime[uidState.state] = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001430 op.proxyUid = proxyUid;
1431 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001432 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001433 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001434 }
1435
1436 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001437 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001438 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001439 final int callingUid = Binder.getCallingUid();
1440 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08001441 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
1442 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001443 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08001444 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001445 if (ops != null) {
1446 Preconditions.checkArrayElementsInRange(ops, 0,
1447 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
1448 }
1449 if (callback == null) {
1450 return;
1451 }
1452 synchronized (this) {
1453 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
1454 if (callbacks == null) {
1455 callbacks = new SparseArray<>();
1456 mActiveWatchers.put(callback.asBinder(), callbacks);
1457 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001458 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
1459 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001460 for (int op : ops) {
1461 callbacks.put(op, activeCallback);
1462 }
1463 }
1464 }
1465
1466 @Override
1467 public void stopWatchingActive(IAppOpsActiveCallback callback) {
1468 if (callback == null) {
1469 return;
1470 }
1471 synchronized (this) {
1472 final SparseArray<ActiveCallback> activeCallbacks =
1473 mActiveWatchers.remove(callback.asBinder());
1474 if (activeCallbacks == null) {
1475 return;
1476 }
1477 final int callbackCount = activeCallbacks.size();
1478 for (int i = 0; i < callbackCount; i++) {
1479 // Apps ops are mapped to a singleton
1480 if (i == 0) {
1481 activeCallbacks.valueAt(i).destroy();
1482 }
1483 }
1484 }
1485 }
1486
1487 @Override
Svet Ganovf7b47252018-02-26 11:11:27 -08001488 public int startOperation(IBinder token, int code, int uid, String packageName,
1489 boolean startIfModeDefault) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001490 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001491 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001492 String resolvedPackageName = resolvePackageName(uid, packageName);
1493 if (resolvedPackageName == null) {
1494 return AppOpsManager.MODE_IGNORED;
1495 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001496 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001497 synchronized (this) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001498 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
Yohei Yukawaa965d652017-10-12 15:02:26 -07001499 false /* uidMismatchExpected */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001500 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001501 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001502 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001503 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001504 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001505 final Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001506 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001507 return AppOpsManager.MODE_IGNORED;
1508 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001509 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001510 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001511 // If there is a non-default per UID policy (we set UID op mode only if
1512 // non-default) it takes over, otherwise use the per package policy.
1513 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001514 final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08001515 if (uidMode != AppOpsManager.MODE_ALLOWED
1516 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001517 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07001518 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001519 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001520 op.rejectTime[uidState.state] = System.currentTimeMillis();
Svet Ganov2af57082015-07-30 08:44:20 -07001521 return uidMode;
1522 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001523 } else {
1524 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001525 final int mode = switchOp.getMode();
1526 if (mode != AppOpsManager.MODE_ALLOWED
1527 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
1528 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001529 + switchCode + " (" + code + ") uid " + uid + " package "
1530 + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001531 op.rejectTime[uidState.state] = System.currentTimeMillis();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001532 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001533 }
Svet Ganov2af57082015-07-30 08:44:20 -07001534 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001535 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001536 + " package " + resolvedPackageName);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001537 if (op.startNesting == 0) {
1538 op.startRealtime = SystemClock.elapsedRealtime();
1539 op.time[uidState.state] = System.currentTimeMillis();
1540 op.rejectTime[uidState.state] = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001541 op.duration = -1;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001542 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001543 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001544 op.startNesting++;
1545 uidState.startNesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001546 if (client.mStartedOps != null) {
1547 client.mStartedOps.add(op);
1548 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001549 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001550
1551 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001552 }
1553
1554 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001555 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001556 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001557 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001558 String resolvedPackageName = resolvePackageName(uid, packageName);
1559 if (resolvedPackageName == null) {
1560 return;
1561 }
1562 if (!(token instanceof ClientState)) {
1563 return;
1564 }
1565 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001566 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001567 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001568 if (op == null) {
1569 return;
1570 }
Svet Ganovf7b47252018-02-26 11:11:27 -08001571 if (!client.mStartedOps.remove(op)) {
Svet Ganovf5d5af12018-03-18 11:51:17 -07001572 // We finish ops when packages get removed to guarantee no dangling
1573 // started ops. However, some part of the system may asynchronously
1574 // finish ops for an already gone package. Hence, finishing an op
1575 // for a non existing package is fine and we don't log as a wtf.
1576 final long identity = Binder.clearCallingIdentity();
1577 try {
1578 if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
1579 resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
1580 Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
1581 + " for non-existing package=" + resolvedPackageName
1582 + " in uid=" + uid);
1583 return;
1584 }
1585 } finally {
1586 Binder.restoreCallingIdentity(identity);
1587 }
1588 Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
1589 + op.packageName + " op=" + AppOpsManager.opToName(op.op));
Svet Ganov31d83ae2018-03-15 10:45:56 -07001590 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001591 }
Svet Ganova7a0db62018-02-27 20:08:01 -08001592 finishOperationLocked(op, /*finishNested*/ false);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001593 if (op.startNesting <= 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001594 scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
1595 }
1596 }
1597 }
1598
1599 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
1600 boolean active) {
1601 ArraySet<ActiveCallback> dispatchedCallbacks = null;
1602 final int callbackListCount = mActiveWatchers.size();
1603 for (int i = 0; i < callbackListCount; i++) {
1604 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
1605 ActiveCallback callback = callbacks.get(code);
1606 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001607 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08001608 continue;
1609 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001610 if (dispatchedCallbacks == null) {
1611 dispatchedCallbacks = new ArraySet<>();
1612 }
1613 dispatchedCallbacks.add(callback);
1614 }
1615 }
1616 if (dispatchedCallbacks == null) {
1617 return;
1618 }
1619 mHandler.sendMessage(PooledLambda.obtainMessage(
1620 AppOpsService::notifyOpActiveChanged,
1621 this, dispatchedCallbacks, code, uid, packageName, active));
1622 }
1623
1624 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
1625 int code, int uid, String packageName, boolean active) {
1626 // There are components watching for mode changes such as window manager
1627 // and location manager which are in our process. The callbacks in these
1628 // components may require permissions our remote caller does not have.
1629 final long identity = Binder.clearCallingIdentity();
1630 try {
1631 final int callbackCount = callbacks.size();
1632 for (int i = 0; i < callbackCount; i++) {
1633 final ActiveCallback callback = callbacks.valueAt(i);
1634 try {
1635 callback.mCallback.opActiveChanged(code, uid, packageName, active);
1636 } catch (RemoteException e) {
1637 /* do nothing */
1638 }
1639 }
1640 } finally {
1641 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001642 }
1643 }
1644
Svet Ganovb9d71a62015-04-30 10:38:13 -07001645 @Override
1646 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001647 if (permission == null) {
1648 return AppOpsManager.OP_NONE;
1649 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07001650 return AppOpsManager.permissionToOpCode(permission);
1651 }
1652
Svet Ganova7a0db62018-02-27 20:08:01 -08001653 void finishOperationLocked(Op op, boolean finishNested) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001654 if (op.startNesting <= 1 || finishNested) {
1655 if (op.startNesting == 1 || finishNested) {
1656 op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
1657 op.time[op.uidState.state] = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001658 } else {
1659 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1660 + op.packageName + " code " + op.op + " time=" + op.time
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001661 + " duration=" + op.duration + " nesting=" + op.startNesting);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001662 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001663 if (op.startNesting >= 1) {
1664 op.uidState.startNesting -= op.startNesting;
1665 }
1666 op.startNesting = 0;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001667 } else {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001668 op.startNesting--;
1669 op.uidState.startNesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001670 }
1671 }
1672
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001673 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001674 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001675 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001676 }
1677 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001678 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001679 }
1680 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1681 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001682 }
1683
Dianne Hackborn961321f2013-02-05 17:22:41 -08001684 private void verifyIncomingOp(int op) {
1685 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1686 return;
1687 }
1688 throw new IllegalArgumentException("Bad operation #" + op);
1689 }
1690
Svet Ganov2af57082015-07-30 08:44:20 -07001691 private UidState getUidStateLocked(int uid, boolean edit) {
1692 UidState uidState = mUidStates.get(uid);
1693 if (uidState == null) {
1694 if (!edit) {
1695 return null;
1696 }
1697 uidState = new UidState(uid);
1698 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001699 } else {
1700 if (uidState.pendingStateCommitTime != 0) {
1701 if (uidState.pendingStateCommitTime < mLastUptime) {
1702 uidState.state = uidState.pendingState;
1703 uidState.pendingStateCommitTime = 0;
1704 } else {
1705 mLastUptime = SystemClock.uptimeMillis();
1706 if (uidState.pendingStateCommitTime < mLastUptime) {
1707 uidState.state = uidState.pendingState;
1708 uidState.pendingStateCommitTime = 0;
1709 }
1710 }
1711 }
Svet Ganov2af57082015-07-30 08:44:20 -07001712 }
1713 return uidState;
1714 }
1715
Yohei Yukawaa965d652017-10-12 15:02:26 -07001716 private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
1717 boolean uidMismatchExpected) {
Svet Ganov2af57082015-07-30 08:44:20 -07001718 UidState uidState = getUidStateLocked(uid, edit);
1719 if (uidState == null) {
1720 return null;
1721 }
1722
1723 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001724 if (!edit) {
1725 return null;
1726 }
Svet Ganov2af57082015-07-30 08:44:20 -07001727 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001728 }
Svet Ganov2af57082015-07-30 08:44:20 -07001729
1730 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001731 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001732 if (!edit) {
1733 return null;
1734 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001735 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001736 // This is the first time we have seen this package name under this uid,
1737 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08001738 if (uid != 0) {
1739 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001740 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001741 int pkgUid = -1;
1742 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04001743 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07001744 .getApplicationInfo(packageName,
1745 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1746 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04001747 if (appInfo != null) {
1748 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001749 isPrivileged = (appInfo.privateFlags
1750 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001751 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08001752 pkgUid = resolveUid(packageName);
1753 if (pkgUid >= 0) {
Chien-Yu Chen75cade02016-01-11 10:56:21 -08001754 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04001755 }
Dianne Hackborn713df152013-05-17 11:27:57 -07001756 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001757 } catch (RemoteException e) {
1758 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001759 }
1760 if (pkgUid != uid) {
1761 // Oops! The package name is not valid for the uid they are calling
1762 // under. Abort.
Yohei Yukawaa965d652017-10-12 15:02:26 -07001763 if (!uidMismatchExpected) {
1764 RuntimeException ex = new RuntimeException("here");
1765 ex.fillInStackTrace();
1766 Slog.w(TAG, "Bad call: specified package " + packageName
1767 + " under uid " + uid + " but it is really " + pkgUid, ex);
1768 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001769 return null;
1770 }
1771 } finally {
1772 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001773 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001774 }
Svet Ganov2af57082015-07-30 08:44:20 -07001775 ops = new Ops(packageName, uidState, isPrivileged);
1776 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001777 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001778 return ops;
1779 }
1780
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001781 private void scheduleWriteLocked() {
1782 if (!mWriteScheduled) {
1783 mWriteScheduled = true;
1784 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1785 }
1786 }
1787
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001788 private void scheduleFastWriteLocked() {
1789 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001790 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001791 mFastWriteScheduled = true;
1792 mHandler.removeCallbacks(mWriteRunner);
1793 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001794 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001795 }
1796
Dianne Hackborn72e39832013-01-18 18:36:09 -08001797 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001798 Ops ops = getOpsRawLocked(uid, packageName, edit,
1799 false /* uidMismatchExpected */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001800 if (ops == null) {
1801 return null;
1802 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001803 return getOpLocked(ops, code, edit);
1804 }
1805
1806 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001807 Op op = ops.get(code);
1808 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001809 if (!edit) {
1810 return null;
1811 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001812 op = new Op(ops.uidState, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001813 ops.put(code, op);
1814 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001815 if (edit) {
1816 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001817 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001818 return op;
1819 }
1820
Svet Ganov442ed572016-08-17 17:29:43 -07001821 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04001822 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001823 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08001824
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001825 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08001826 // For each client, check that the given op is not restricted, or that the given
1827 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07001828 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07001829 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
1830 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
1831 // If we are the system, bypass user restrictions for certain codes
1832 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07001833 Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
1834 false /* uidMismatchExpected */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07001835 if ((ops != null) && ops.isPrivileged) {
1836 return false;
1837 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08001838 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08001839 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001840 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04001841 }
Jason Monk62062992014-05-06 09:55:28 -04001842 }
1843 return false;
1844 }
1845
Dianne Hackborn35654b62013-01-14 17:38:02 -08001846 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001847 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001848 synchronized (mFile) {
1849 synchronized (this) {
1850 FileInputStream stream;
1851 try {
1852 stream = mFile.openRead();
1853 } catch (FileNotFoundException e) {
1854 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
1855 return;
1856 }
1857 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001858 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001859 try {
1860 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001861 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08001862 int type;
1863 while ((type = parser.next()) != XmlPullParser.START_TAG
1864 && type != XmlPullParser.END_DOCUMENT) {
1865 ;
1866 }
1867
1868 if (type != XmlPullParser.START_TAG) {
1869 throw new IllegalStateException("no start tag found");
1870 }
1871
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001872 final String versionString = parser.getAttributeValue(null, "v");
1873 if (versionString != null) {
1874 oldVersion = Integer.parseInt(versionString);
1875 }
1876
Dianne Hackborn35654b62013-01-14 17:38:02 -08001877 int outerDepth = parser.getDepth();
1878 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1879 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1880 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1881 continue;
1882 }
1883
1884 String tagName = parser.getName();
1885 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001886 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07001887 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07001888 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001889 } else {
1890 Slog.w(TAG, "Unknown element under <app-ops>: "
1891 + parser.getName());
1892 XmlUtils.skipCurrentTag(parser);
1893 }
1894 }
1895 success = true;
1896 } catch (IllegalStateException e) {
1897 Slog.w(TAG, "Failed parsing " + e);
1898 } catch (NullPointerException e) {
1899 Slog.w(TAG, "Failed parsing " + e);
1900 } catch (NumberFormatException e) {
1901 Slog.w(TAG, "Failed parsing " + e);
1902 } catch (XmlPullParserException e) {
1903 Slog.w(TAG, "Failed parsing " + e);
1904 } catch (IOException e) {
1905 Slog.w(TAG, "Failed parsing " + e);
1906 } catch (IndexOutOfBoundsException e) {
1907 Slog.w(TAG, "Failed parsing " + e);
1908 } finally {
1909 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07001910 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001911 }
1912 try {
1913 stream.close();
1914 } catch (IOException e) {
1915 }
1916 }
1917 }
1918 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001919 synchronized (this) {
1920 upgradeLocked(oldVersion);
1921 }
1922 }
1923
1924 private void upgradeRunAnyInBackgroundLocked() {
1925 for (int i = 0; i < mUidStates.size(); i++) {
1926 final UidState uidState = mUidStates.valueAt(i);
1927 if (uidState == null) {
1928 continue;
1929 }
1930 if (uidState.opModes != null) {
1931 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
1932 if (idx >= 0) {
1933 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
1934 uidState.opModes.valueAt(idx));
1935 }
1936 }
1937 if (uidState.pkgOps == null) {
1938 continue;
1939 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001940 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001941 for (int j = 0; j < uidState.pkgOps.size(); j++) {
1942 Ops ops = uidState.pkgOps.valueAt(j);
1943 if (ops != null) {
1944 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
1945 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001946 final Op copy = new Op(op.uidState, op.packageName,
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001947 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
1948 copy.mode = op.mode;
1949 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001950 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001951 }
1952 }
1953 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001954 if (changed) {
1955 uidState.evalForegroundOps();
1956 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07001957 }
1958 }
1959
1960 private void upgradeLocked(int oldVersion) {
1961 if (oldVersion >= CURRENT_VERSION) {
1962 return;
1963 }
1964 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
1965 switch (oldVersion) {
1966 case NO_VERSION:
1967 upgradeRunAnyInBackgroundLocked();
1968 // fall through
1969 case 1:
1970 // for future upgrades
1971 }
1972 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001973 }
1974
Svet Ganov2af57082015-07-30 08:44:20 -07001975 void readUidOps(XmlPullParser parser) throws NumberFormatException,
1976 XmlPullParserException, IOException {
1977 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1978 int outerDepth = parser.getDepth();
1979 int type;
1980 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1981 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1982 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1983 continue;
1984 }
1985
1986 String tagName = parser.getName();
1987 if (tagName.equals("op")) {
1988 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
1989 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
1990 UidState uidState = getUidStateLocked(uid, true);
1991 if (uidState.opModes == null) {
1992 uidState.opModes = new SparseIntArray();
1993 }
1994 uidState.opModes.put(code, mode);
1995 } else {
1996 Slog.w(TAG, "Unknown element under <uid-ops>: "
1997 + parser.getName());
1998 XmlUtils.skipCurrentTag(parser);
1999 }
2000 }
2001 }
2002
Dave Burke0997c5bd2013-08-02 20:25:02 +00002003 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002004 XmlPullParserException, IOException {
2005 String pkgName = parser.getAttributeValue(null, "n");
2006 int outerDepth = parser.getDepth();
2007 int type;
2008 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2009 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2010 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2011 continue;
2012 }
2013
2014 String tagName = parser.getName();
2015 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00002016 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002017 } else {
2018 Slog.w(TAG, "Unknown element under <pkg>: "
2019 + parser.getName());
2020 XmlUtils.skipCurrentTag(parser);
2021 }
2022 }
2023 }
2024
Dave Burke0997c5bd2013-08-02 20:25:02 +00002025 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08002026 XmlPullParserException, IOException {
2027 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04002028 String isPrivilegedString = parser.getAttributeValue(null, "p");
2029 boolean isPrivileged = false;
2030 if (isPrivilegedString == null) {
2031 try {
2032 IPackageManager packageManager = ActivityThread.getPackageManager();
2033 if (packageManager != null) {
2034 ApplicationInfo appInfo = ActivityThread.getPackageManager()
2035 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
2036 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002037 isPrivileged = (appInfo.privateFlags
2038 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04002039 }
2040 } else {
2041 // Could not load data, don't add to cache so it will be loaded later.
2042 return;
2043 }
2044 } catch (RemoteException e) {
2045 Slog.w(TAG, "Could not contact PackageManager", e);
2046 }
2047 } else {
2048 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
2049 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002050 int outerDepth = parser.getDepth();
2051 int type;
2052 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2053 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2054 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2055 continue;
2056 }
2057
2058 String tagName = parser.getName();
2059 if (tagName.equals("op")) {
Svet Ganov2af57082015-07-30 08:44:20 -07002060 UidState uidState = getUidStateLocked(uid, true);
2061 if (uidState.pkgOps == null) {
2062 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002063 }
Svet Ganov2af57082015-07-30 08:44:20 -07002064
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002065 Op op = new Op(uidState, pkgName,
2066 Integer.parseInt(parser.getAttributeValue(null, "n")));
2067
2068 for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
2069 final String name = parser.getAttributeName(i);
2070 final String value = parser.getAttributeValue(i);
2071 switch (name) {
2072 case "m":
2073 op.mode = Integer.parseInt(value);
2074 break;
2075 case "d":
2076 op.duration = Integer.parseInt(value);
2077 break;
2078 case "pu":
2079 op.proxyUid = Integer.parseInt(value);
2080 break;
2081 case "pp":
2082 op.proxyPackageName = value;
2083 break;
2084 case "tp":
2085 op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
2086 break;
2087 case "tt":
2088 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2089 break;
2090 case "tfs":
2091 op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2092 = Long.parseLong(value);
2093 break;
2094 case "tf":
2095 op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
2096 break;
2097 case "tb":
2098 op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
2099 break;
2100 case "tc":
2101 op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
2102 break;
2103 case "rp":
2104 op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
2105 = Long.parseLong(value);
2106 break;
2107 case "rt":
2108 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2109 break;
2110 case "rfs":
2111 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
2112 = Long.parseLong(value);
2113 break;
2114 case "rf":
2115 op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
2116 = Long.parseLong(value);
2117 break;
2118 case "rb":
2119 op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
2120 = Long.parseLong(value);
2121 break;
2122 case "rc":
2123 op.rejectTime[AppOpsManager.UID_STATE_CACHED]
2124 = Long.parseLong(value);
2125 break;
2126 case "t":
2127 // Backwards compat.
2128 op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2129 break;
2130 case "r":
2131 // Backwards compat.
2132 op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
2133 break;
2134 default:
2135 Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
2136 break;
2137 }
2138 }
2139
Svet Ganov2af57082015-07-30 08:44:20 -07002140 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002141 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002142 ops = new Ops(pkgName, uidState, isPrivileged);
2143 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002144 }
2145 ops.put(op.op, op);
2146 } else {
2147 Slog.w(TAG, "Unknown element under <pkg>: "
2148 + parser.getName());
2149 XmlUtils.skipCurrentTag(parser);
2150 }
2151 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002152 UidState uidState = getUidStateLocked(uid, false);
2153 if (uidState != null) {
2154 uidState.evalForegroundOps();
2155 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002156 }
2157
2158 void writeState() {
2159 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08002160 FileOutputStream stream;
2161 try {
2162 stream = mFile.startWrite();
2163 } catch (IOException e) {
2164 Slog.w(TAG, "Failed to write state: " + e);
2165 return;
2166 }
2167
Dianne Hackborne17b4452018-01-10 13:15:40 -08002168 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
2169
Dianne Hackborn35654b62013-01-14 17:38:02 -08002170 try {
2171 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002172 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08002173 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002174 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07002175 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07002176
2177 final int uidStateCount = mUidStates.size();
2178 for (int i = 0; i < uidStateCount; i++) {
2179 UidState uidState = mUidStates.valueAt(i);
2180 if (uidState.opModes != null && uidState.opModes.size() > 0) {
2181 out.startTag(null, "uid");
2182 out.attribute(null, "n", Integer.toString(uidState.uid));
2183 SparseIntArray uidOpModes = uidState.opModes;
2184 final int opCount = uidOpModes.size();
2185 for (int j = 0; j < opCount; j++) {
2186 final int op = uidOpModes.keyAt(j);
2187 final int mode = uidOpModes.valueAt(j);
2188 out.startTag(null, "op");
2189 out.attribute(null, "n", Integer.toString(op));
2190 out.attribute(null, "m", Integer.toString(mode));
2191 out.endTag(null, "op");
2192 }
2193 out.endTag(null, "uid");
2194 }
2195 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002196
2197 if (allOps != null) {
2198 String lastPkg = null;
2199 for (int i=0; i<allOps.size(); i++) {
2200 AppOpsManager.PackageOps pkg = allOps.get(i);
2201 if (!pkg.getPackageName().equals(lastPkg)) {
2202 if (lastPkg != null) {
2203 out.endTag(null, "pkg");
2204 }
2205 lastPkg = pkg.getPackageName();
2206 out.startTag(null, "pkg");
2207 out.attribute(null, "n", lastPkg);
2208 }
2209 out.startTag(null, "uid");
2210 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04002211 synchronized (this) {
Yohei Yukawaa965d652017-10-12 15:02:26 -07002212 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
2213 false /* edit */, false /* uidMismatchExpected */);
Jason Monk1c7c3192014-06-26 12:52:18 -04002214 // Should always be present as the list of PackageOps is generated
2215 // from Ops.
2216 if (ops != null) {
2217 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
2218 } else {
2219 out.attribute(null, "p", Boolean.toString(false));
2220 }
2221 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002222 List<AppOpsManager.OpEntry> ops = pkg.getOps();
2223 for (int j=0; j<ops.size(); j++) {
2224 AppOpsManager.OpEntry op = ops.get(j);
2225 out.startTag(null, "op");
2226 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07002227 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002228 out.attribute(null, "m", Integer.toString(op.getMode()));
2229 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002230 for (int k = 0; k < _NUM_UID_STATE; k++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002231 final long time = op.getLastTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002232 if (time != 0) {
2233 out.attribute(null, UID_STATE_TIME_ATTRS[k],
2234 Long.toString(time));
2235 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002236 final long rejectTime = op.getLastRejectTimeFor(k);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002237 if (rejectTime != 0) {
2238 out.attribute(null, UID_STATE_REJECT_ATTRS[k],
2239 Long.toString(rejectTime));
2240 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002241 }
2242 int dur = op.getDuration();
2243 if (dur != 0) {
2244 out.attribute(null, "d", Integer.toString(dur));
2245 }
Svet Ganov99b60432015-06-27 13:15:22 -07002246 int proxyUid = op.getProxyUid();
2247 if (proxyUid != -1) {
2248 out.attribute(null, "pu", Integer.toString(proxyUid));
2249 }
2250 String proxyPackageName = op.getProxyPackageName();
2251 if (proxyPackageName != null) {
2252 out.attribute(null, "pp", proxyPackageName);
2253 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08002254 out.endTag(null, "op");
2255 }
2256 out.endTag(null, "uid");
2257 }
2258 if (lastPkg != null) {
2259 out.endTag(null, "pkg");
2260 }
2261 }
2262
2263 out.endTag(null, "app-ops");
2264 out.endDocument();
2265 mFile.finishWrite(stream);
2266 } catch (IOException e) {
2267 Slog.w(TAG, "Failed to write state, restoring backup.", e);
2268 mFile.failWrite(stream);
2269 }
2270 }
2271 }
2272
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002273 static class Shell extends ShellCommand {
2274 final IAppOpsService mInterface;
2275 final AppOpsService mInternal;
2276
2277 int userId = UserHandle.USER_SYSTEM;
2278 String packageName;
2279 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002280 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002281 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002282 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002283 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002284 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002285 final static Binder sBinder = new Binder();
2286 IBinder mToken;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002287
2288 Shell(IAppOpsService iface, AppOpsService internal) {
2289 mInterface = iface;
2290 mInternal = internal;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002291 try {
2292 mToken = mInterface.getToken(sBinder);
2293 } catch (RemoteException e) {
2294 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002295 }
2296
2297 @Override
2298 public int onCommand(String cmd) {
2299 return onShellCommand(this, cmd);
2300 }
2301
2302 @Override
2303 public void onHelp() {
2304 PrintWriter pw = getOutPrintWriter();
2305 dumpCommandHelp(pw);
2306 }
2307
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002308 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002309 try {
2310 return AppOpsManager.strOpToOp(op);
2311 } catch (IllegalArgumentException e) {
2312 }
2313 try {
2314 return Integer.parseInt(op);
2315 } catch (NumberFormatException e) {
2316 }
2317 try {
2318 return AppOpsManager.strDebugOpToOp(op);
2319 } catch (IllegalArgumentException e) {
2320 err.println("Error: " + e.getMessage());
2321 return -1;
2322 }
2323 }
2324
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002325 int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002326 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
2327 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002328 return i;
2329 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002330 }
2331 try {
2332 return Integer.parseInt(modeStr);
2333 } catch (NumberFormatException e) {
2334 }
2335 err.println("Error: Mode " + modeStr + " is not valid");
2336 return -1;
2337 }
2338
2339 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
2340 userId = UserHandle.USER_CURRENT;
2341 opStr = null;
2342 modeStr = null;
2343 for (String argument; (argument = getNextArg()) != null;) {
2344 if ("--user".equals(argument)) {
2345 userId = UserHandle.parseUserArg(getNextArgRequired());
2346 } else {
2347 if (opStr == null) {
2348 opStr = argument;
2349 } else if (modeStr == null) {
2350 modeStr = argument;
2351 break;
2352 }
2353 }
2354 }
2355 if (opStr == null) {
2356 err.println("Error: Operation not specified.");
2357 return -1;
2358 }
2359 op = strOpToOp(opStr, err);
2360 if (op < 0) {
2361 return -1;
2362 }
2363 if (modeStr != null) {
2364 if ((mode=strModeToMode(modeStr, err)) < 0) {
2365 return -1;
2366 }
2367 } else {
2368 mode = defMode;
2369 }
2370 return 0;
2371 }
2372
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002373 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
2374 userId = UserHandle.USER_CURRENT;
2375 packageName = null;
2376 opStr = null;
2377 for (String argument; (argument = getNextArg()) != null;) {
2378 if ("--user".equals(argument)) {
2379 userId = UserHandle.parseUserArg(getNextArgRequired());
2380 } else {
2381 if (packageName == null) {
2382 packageName = argument;
2383 } else if (opStr == null) {
2384 opStr = argument;
2385 break;
2386 }
2387 }
2388 }
2389 if (packageName == null) {
2390 err.println("Error: Package name not specified.");
2391 return -1;
2392 } else if (opStr == null && reqOp) {
2393 err.println("Error: Operation not specified.");
2394 return -1;
2395 }
2396 if (opStr != null) {
2397 op = strOpToOp(opStr, err);
2398 if (op < 0) {
2399 return -1;
2400 }
2401 } else {
2402 op = AppOpsManager.OP_NONE;
2403 }
2404 if (userId == UserHandle.USER_CURRENT) {
2405 userId = ActivityManager.getCurrentUser();
2406 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002407 nonpackageUid = -1;
2408 try {
2409 nonpackageUid = Integer.parseInt(packageName);
2410 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002411 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002412 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
2413 && packageName.indexOf('.') < 0) {
2414 int i = 1;
2415 while (i < packageName.length() && packageName.charAt(i) >= '0'
2416 && packageName.charAt(i) <= '9') {
2417 i++;
2418 }
2419 if (i > 1 && i < packageName.length()) {
2420 String userStr = packageName.substring(1, i);
2421 try {
2422 int user = Integer.parseInt(userStr);
2423 char type = packageName.charAt(i);
2424 i++;
2425 int startTypeVal = i;
2426 while (i < packageName.length() && packageName.charAt(i) >= '0'
2427 && packageName.charAt(i) <= '9') {
2428 i++;
2429 }
2430 if (i > startTypeVal) {
2431 String typeValStr = packageName.substring(startTypeVal, i);
2432 try {
2433 int typeVal = Integer.parseInt(typeValStr);
2434 if (type == 'a') {
2435 nonpackageUid = UserHandle.getUid(user,
2436 typeVal + Process.FIRST_APPLICATION_UID);
2437 } else if (type == 's') {
2438 nonpackageUid = UserHandle.getUid(user, typeVal);
2439 }
2440 } catch (NumberFormatException e) {
2441 }
2442 }
2443 } catch (NumberFormatException e) {
2444 }
2445 }
2446 }
2447 if (nonpackageUid != -1) {
2448 packageName = null;
2449 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08002450 packageUid = resolveUid(packageName);
2451 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002452 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
2453 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
2454 }
2455 if (packageUid < 0) {
2456 err.println("Error: No UID for " + packageName + " in user " + userId);
2457 return -1;
2458 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002459 }
2460 return 0;
2461 }
2462 }
2463
2464 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07002465 FileDescriptor err, String[] args, ShellCallback callback,
2466 ResultReceiver resultReceiver) {
2467 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002468 }
2469
2470 static void dumpCommandHelp(PrintWriter pw) {
2471 pw.println("AppOps service (appops) commands:");
2472 pw.println(" help");
2473 pw.println(" Print this help text.");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002474 pw.println(" start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2475 pw.println(" Starts a given operation for a particular application.");
2476 pw.println(" stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
2477 pw.println(" Stops a given operation for a particular application.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002478 pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002479 pw.println(" Set the mode for a particular application and operation.");
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002480 pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002481 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002482 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
2483 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002484 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
2485 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002486 pw.println(" write-settings");
2487 pw.println(" Immediately write pending changes to storage.");
2488 pw.println(" read-settings");
2489 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002490 pw.println(" options:");
2491 pw.println(" <PACKAGE> an Android package name.");
2492 pw.println(" <OP> an AppOps operation.");
2493 pw.println(" <MODE> one of allow, ignore, deny, or default");
2494 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
2495 pw.println(" specified, the current user is assumed.");
2496 }
2497
2498 static int onShellCommand(Shell shell, String cmd) {
2499 if (cmd == null) {
2500 return shell.handleDefaultCommands(cmd);
2501 }
2502 PrintWriter pw = shell.getOutPrintWriter();
2503 PrintWriter err = shell.getErrPrintWriter();
2504 try {
2505 switch (cmd) {
2506 case "set": {
2507 int res = shell.parseUserPackageOp(true, err);
2508 if (res < 0) {
2509 return res;
2510 }
2511 String modeStr = shell.getNextArg();
2512 if (modeStr == null) {
2513 err.println("Error: Mode not specified.");
2514 return -1;
2515 }
2516
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002517 final int mode = shell.strModeToMode(modeStr, err);
2518 if (mode < 0) {
2519 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002520 }
2521
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002522 if (shell.packageName != null) {
2523 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
2524 mode);
2525 } else {
2526 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
2527 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002528 return 0;
2529 }
2530 case "get": {
2531 int res = shell.parseUserPackageOp(false, err);
2532 if (res < 0) {
2533 return res;
2534 }
2535
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002536 List<AppOpsManager.PackageOps> ops;
2537 if (shell.packageName != null) {
2538 ops = shell.mInterface.getOpsForPackage(
2539 shell.packageUid, shell.packageName,
2540 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2541 } else {
2542 ops = shell.mInterface.getUidOps(
2543 shell.nonpackageUid,
2544 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
2545 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002546 if (ops == null || ops.size() <= 0) {
2547 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08002548 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002549 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08002550 AppOpsManager.opToDefaultMode(shell.op)));
2551 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002552 return 0;
2553 }
2554 final long now = System.currentTimeMillis();
2555 for (int i=0; i<ops.size(); i++) {
2556 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2557 for (int j=0; j<entries.size(); j++) {
2558 AppOpsManager.OpEntry ent = entries.get(j);
2559 pw.print(AppOpsManager.opToName(ent.getOp()));
2560 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002561 pw.print(AppOpsManager.modeToName(ent.getMode()));
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002562 if (ent.getTime() != 0) {
2563 pw.print("; time=");
2564 TimeUtils.formatDuration(now - ent.getTime(), pw);
2565 pw.print(" ago");
2566 }
2567 if (ent.getRejectTime() != 0) {
2568 pw.print("; rejectTime=");
2569 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
2570 pw.print(" ago");
2571 }
2572 if (ent.getDuration() == -1) {
2573 pw.print(" (running)");
2574 } else if (ent.getDuration() != 0) {
2575 pw.print("; duration=");
2576 TimeUtils.formatDuration(ent.getDuration(), pw);
2577 }
2578 pw.println();
2579 }
2580 }
2581 return 0;
2582 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07002583 case "query-op": {
2584 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
2585 if (res < 0) {
2586 return res;
2587 }
2588 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
2589 new int[] {shell.op});
2590 if (ops == null || ops.size() <= 0) {
2591 pw.println("No operations.");
2592 return 0;
2593 }
2594 for (int i=0; i<ops.size(); i++) {
2595 final AppOpsManager.PackageOps pkg = ops.get(i);
2596 boolean hasMatch = false;
2597 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
2598 for (int j=0; j<entries.size(); j++) {
2599 AppOpsManager.OpEntry ent = entries.get(j);
2600 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
2601 hasMatch = true;
2602 break;
2603 }
2604 }
2605 if (hasMatch) {
2606 pw.println(pkg.getPackageName());
2607 }
2608 }
2609 return 0;
2610 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002611 case "reset": {
2612 String packageName = null;
2613 int userId = UserHandle.USER_CURRENT;
2614 for (String argument; (argument = shell.getNextArg()) != null;) {
2615 if ("--user".equals(argument)) {
2616 String userStr = shell.getNextArgRequired();
2617 userId = UserHandle.parseUserArg(userStr);
2618 } else {
2619 if (packageName == null) {
2620 packageName = argument;
2621 } else {
2622 err.println("Error: Unsupported argument: " + argument);
2623 return -1;
2624 }
2625 }
2626 }
2627
2628 if (userId == UserHandle.USER_CURRENT) {
2629 userId = ActivityManager.getCurrentUser();
2630 }
2631
2632 shell.mInterface.resetAllModes(userId, packageName);
2633 pw.print("Reset all modes for: ");
2634 if (userId == UserHandle.USER_ALL) {
2635 pw.print("all users");
2636 } else {
2637 pw.print("user "); pw.print(userId);
2638 }
2639 pw.print(", ");
2640 if (packageName == null) {
2641 pw.println("all packages");
2642 } else {
2643 pw.print("package "); pw.println(packageName);
2644 }
2645 return 0;
2646 }
2647 case "write-settings": {
2648 shell.mInternal.mContext.enforcePermission(
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08002649 android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002650 Binder.getCallingPid(), Binder.getCallingUid(), null);
2651 long token = Binder.clearCallingIdentity();
2652 try {
2653 synchronized (shell.mInternal) {
2654 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
2655 }
2656 shell.mInternal.writeState();
2657 pw.println("Current settings written.");
2658 } finally {
2659 Binder.restoreCallingIdentity(token);
2660 }
2661 return 0;
2662 }
2663 case "read-settings": {
2664 shell.mInternal.mContext.enforcePermission(
Dianne Hackbornbf1b57d2018-03-07 12:42:47 -08002665 android.Manifest.permission.MANAGE_APP_OPS_MODES,
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002666 Binder.getCallingPid(), Binder.getCallingUid(), null);
2667 long token = Binder.clearCallingIdentity();
2668 try {
2669 shell.mInternal.readState();
2670 pw.println("Last settings read.");
2671 } finally {
2672 Binder.restoreCallingIdentity(token);
2673 }
2674 return 0;
2675 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05002676 case "start": {
2677 int res = shell.parseUserPackageOp(true, err);
2678 if (res < 0) {
2679 return res;
2680 }
2681
2682 if (shell.packageName != null) {
2683 shell.mInterface.startOperation(shell.mToken,
2684 shell.op, shell.packageUid, shell.packageName, true);
2685 } else {
2686 return -1;
2687 }
2688 return 0;
2689 }
2690 case "stop": {
2691 int res = shell.parseUserPackageOp(true, err);
2692 if (res < 0) {
2693 return res;
2694 }
2695
2696 if (shell.packageName != null) {
2697 shell.mInterface.finishOperation(shell.mToken,
2698 shell.op, shell.packageUid, shell.packageName);
2699 } else {
2700 return -1;
2701 }
2702 return 0;
2703 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08002704 default:
2705 return shell.handleDefaultCommands(cmd);
2706 }
2707 } catch (RemoteException e) {
2708 pw.println("Remote exception: " + e);
2709 }
2710 return -1;
2711 }
2712
2713 private void dumpHelp(PrintWriter pw) {
2714 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002715 pw.println(" -h");
2716 pw.println(" Print this help text.");
2717 pw.println(" --op [OP]");
2718 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002719 }
2720
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002721 private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
2722 long now, SimpleDateFormat sdf, Date date) {
2723 boolean hasTime = false;
2724 for (int i = 0; i < _NUM_UID_STATE; i++) {
2725 if (times[i] != 0) {
2726 hasTime = true;
2727 break;
2728 }
2729 }
2730 if (!hasTime) {
2731 return;
2732 }
2733 boolean first = true;
2734 for (int i = 0; i < _NUM_UID_STATE; i++) {
2735 if (times[i] != 0) {
2736 pw.print(first ? firstPrefix : prefix);
2737 first = false;
2738 pw.print(UID_STATE_NAMES[i]);
2739 pw.print(" = ");
2740 date.setTime(times[i]);
2741 pw.print(sdf.format(date));
2742 pw.print(" (");
2743 TimeUtils.formatDuration(times[i]-now, pw);
2744 pw.println(")");
2745 }
2746 }
2747 }
2748
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002749 @Override
2750 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002751 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002752
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002753 int dumpOp = -1;
2754
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002755 if (args != null) {
2756 for (int i=0; i<args.length; i++) {
2757 String arg = args[i];
2758 if ("-h".equals(arg)) {
2759 dumpHelp(pw);
2760 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07002761 } else if ("-a".equals(arg)) {
2762 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002763 } else if ("--op".equals(arg)) {
2764 i++;
2765 if (i >= args.length) {
2766 pw.println("No argument for --op option");
2767 return;
2768 }
2769 dumpOp = Shell.strOpToOp(args[i], pw);
2770 if (dumpOp < 0) {
2771 return;
2772 }
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002773 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
2774 pw.println("Unknown option: " + arg);
2775 return;
2776 } else {
2777 pw.println("Unknown command: " + arg);
2778 return;
2779 }
2780 }
2781 }
2782
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002783 synchronized (this) {
2784 pw.println("Current AppOps Service state:");
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002785 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002786 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002787 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002788 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
2789 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002790 boolean needSep = false;
2791 if (mOpModeWatchers.size() > 0) {
2792 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002793 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002794 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002795 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
2796 continue;
2797 }
2798 if (!printedHeader) {
2799 pw.println(" Op mode watchers:");
2800 printedHeader = true;
2801 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002802 pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
2803 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002804 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002805 for (int j=0; j<callbacks.size(); j++) {
2806 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08002807 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002808 }
2809 }
2810 }
2811 if (mPackageModeWatchers.size() > 0) {
2812 needSep = true;
2813 pw.println(" Package mode watchers:");
2814 for (int i=0; i<mPackageModeWatchers.size(); i++) {
2815 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
2816 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002817 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002818 for (int j=0; j<callbacks.size(); j++) {
2819 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08002820 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002821 }
2822 }
2823 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002824 if (mModeWatchers.size() > 0 && dumpOp < 0) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002825 needSep = true;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002826 pw.println(" All op mode watchers:");
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002827 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002828 pw.print(" ");
2829 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
2830 pw.print(": "); pw.println(mModeWatchers.valueAt(i));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002831 }
2832 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002833 if (mActiveWatchers.size() > 0) {
2834 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002835 boolean printedHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002836 for (int i = 0; i < mActiveWatchers.size(); i++) {
2837 final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
2838 if (activeWatchers.size() <= 0) {
2839 continue;
2840 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002841 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
2842 continue;
2843 }
2844 if (!printedHeader) {
2845 pw.println(" All op active watchers:");
2846 printedHeader = true;
2847 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002848 pw.print(" ");
2849 pw.print(Integer.toHexString(System.identityHashCode(
2850 mActiveWatchers.keyAt(i))));
2851 pw.println(" ->");
2852 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002853 final int opCount = activeWatchers.size();
2854 for (i = 0; i < opCount; i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002855 if (i > 0) {
2856 pw.print(' ');
2857 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002858 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
2859 if (i < opCount - 1) {
2860 pw.print(',');
2861 }
2862 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002863 pw.println("]");
2864 pw.print(" ");
2865 pw.println(activeWatchers.valueAt(0));
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002866 }
2867 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002868 if (mClients.size() > 0) {
2869 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002870 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002871 for (int i=0; i<mClients.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002872 boolean printedClient = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002873 ClientState cs = mClients.valueAt(i);
Svet Ganovf7b47252018-02-26 11:11:27 -08002874 if (cs.mStartedOps.size() > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002875 boolean printedStarted = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002876 for (int j=0; j<cs.mStartedOps.size(); j++) {
2877 Op op = cs.mStartedOps.get(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002878 if (dumpOp >= 0 && op.op != dumpOp) {
2879 continue;
2880 }
2881 if (!printedHeader) {
2882 pw.println(" Clients:");
2883 printedHeader = true;
2884 }
2885 if (!printedClient) {
2886 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
2887 pw.print(" "); pw.println(cs);
2888 printedClient = true;
2889 }
2890 if (!printedStarted) {
2891 pw.println(" Started ops:");
2892 printedStarted = true;
2893 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002894 pw.print(" "); pw.print("uid="); pw.print(op.uid);
2895 pw.print(" pkg="); pw.print(op.packageName);
2896 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
2897 }
2898 }
2899 }
2900 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002901 if (mAudioRestrictions.size() > 0 && dumpOp < 0) {
John Spurlock1af30c72014-03-10 08:33:35 -04002902 boolean printedHeader = false;
2903 for (int o=0; o<mAudioRestrictions.size(); o++) {
2904 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
2905 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
2906 for (int i=0; i<restrictions.size(); i++) {
2907 if (!printedHeader){
2908 pw.println(" Audio Restrictions:");
2909 printedHeader = true;
2910 needSep = true;
2911 }
John Spurlock7b414672014-07-18 13:02:39 -04002912 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04002913 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04002914 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04002915 Restriction r = restrictions.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002916 pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
John Spurlock1af30c72014-03-10 08:33:35 -04002917 if (!r.exceptionPackages.isEmpty()) {
2918 pw.println(" Exceptions:");
2919 for (int j=0; j<r.exceptionPackages.size(); j++) {
2920 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
2921 }
2922 }
2923 }
2924 }
2925 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002926 if (needSep) {
2927 pw.println();
2928 }
Svet Ganov2af57082015-07-30 08:44:20 -07002929 for (int i=0; i<mUidStates.size(); i++) {
2930 UidState uidState = mUidStates.valueAt(i);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002931 final SparseIntArray opModes = uidState.opModes;
2932 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
2933
2934 if (dumpOp >= 0) {
2935 boolean hasOp = uidState.opModes != null
2936 && uidState.opModes.indexOfKey(dumpOp) >= 0;
2937 if (pkgOps != null) {
2938 for (int pkgi = 0; !hasOp && pkgi < pkgOps.size(); pkgi++) {
2939 Ops ops = pkgOps.valueAt(pkgi);
2940 if (ops != null && ops.indexOfKey(dumpOp) >= 0) {
2941 hasOp = true;
2942 continue;
2943 }
2944 }
2945 }
2946 if (!hasOp) {
2947 continue;
2948 }
2949 }
Svet Ganov2af57082015-07-30 08:44:20 -07002950
2951 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002952 pw.print(" state=");
2953 pw.println(UID_STATE_NAMES[uidState.state]);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002954 if (uidState.state != uidState.pendingState) {
2955 pw.print(" pendingState=");
2956 pw.println(UID_STATE_NAMES[uidState.pendingState]);
2957 }
2958 if (uidState.pendingStateCommitTime != 0) {
2959 pw.print(" pendingStateCommitTime=");
2960 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowUptime, pw);
2961 pw.println();
2962 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002963 if (uidState.startNesting != 0) {
2964 pw.print(" startNesting=");
2965 pw.println(uidState.startNesting);
2966 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002967 if (uidState.foregroundOps != null) {
2968 pw.println(" foregroundOps:");
2969 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
2970 pw.print(" ");
2971 pw.println(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
2972 }
2973 }
Svet Ganovee438d42017-01-19 18:04:38 -08002974 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07002975
Svet Ganov2af57082015-07-30 08:44:20 -07002976 if (opModes != null) {
2977 final int opModeCount = opModes.size();
2978 for (int j = 0; j < opModeCount; j++) {
2979 final int code = opModes.keyAt(j);
2980 final int mode = opModes.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002981 if (dumpOp >= 0 && dumpOp != code) {
2982 continue;
2983 }
Svet Ganov2af57082015-07-30 08:44:20 -07002984 pw.print(" "); pw.print(AppOpsManager.opToName(code));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002985 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07002986 }
2987 }
2988
Svet Ganov2af57082015-07-30 08:44:20 -07002989 if (pkgOps == null) {
2990 continue;
2991 }
2992
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002993 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
2994 Ops ops = pkgOps.valueAt(pkgi);
2995 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002996 for (int j=0; j<ops.size(); j++) {
2997 Op op = ops.valueAt(j);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002998 if (dumpOp >= 0 && dumpOp != op.op) {
2999 continue;
3000 }
3001 if (!printedPackage) {
3002 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
3003 printedPackage = true;
3004 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003005 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003006 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
3007 pw.println("): ");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003008 dumpTimesLocked(pw,
3009 " Access: ",
3010 " ", op.time, now, sdf, date);
3011 dumpTimesLocked(pw,
3012 " Reject: ",
3013 " ", op.rejectTime, now, sdf, date);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003014 if (op.duration == -1) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003015 pw.print(" Running start at: ");
3016 TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
3017 pw.println();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003018 } else if (op.duration != 0) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003019 pw.print(" duration=");
3020 TimeUtils.formatDuration(op.duration, pw);
3021 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003022 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003023 if (op.startNesting != 0) {
3024 pw.print(" startNesting=");
3025 pw.println(op.startNesting);
3026 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003027 }
3028 }
3029 }
Svet Ganovee438d42017-01-19 18:04:38 -08003030 if (needSep) {
3031 pw.println();
3032 }
3033
3034 final int userRestrictionCount = mOpUserRestrictions.size();
3035 for (int i = 0; i < userRestrictionCount; i++) {
3036 IBinder token = mOpUserRestrictions.keyAt(i);
3037 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
3038 pw.println(" User restrictions for token " + token + ":");
3039
3040 final int restrictionCount = restrictionState.perUserRestrictions != null
3041 ? restrictionState.perUserRestrictions.size() : 0;
3042 if (restrictionCount > 0) {
3043 pw.println(" Restricted ops:");
3044 for (int j = 0; j < restrictionCount; j++) {
3045 int userId = restrictionState.perUserRestrictions.keyAt(j);
3046 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
3047 if (restrictedOps == null) {
3048 continue;
3049 }
3050 StringBuilder restrictedOpsValue = new StringBuilder();
3051 restrictedOpsValue.append("[");
3052 final int restrictedOpCount = restrictedOps.length;
3053 for (int k = 0; k < restrictedOpCount; k++) {
3054 if (restrictedOps[k]) {
3055 if (restrictedOpsValue.length() > 1) {
3056 restrictedOpsValue.append(", ");
3057 }
3058 restrictedOpsValue.append(AppOpsManager.opToName(k));
3059 }
3060 }
3061 restrictedOpsValue.append("]");
3062 pw.print(" "); pw.print("user: "); pw.print(userId);
3063 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
3064 }
3065 }
3066
3067 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
3068 ? restrictionState.perUserExcludedPackages.size() : 0;
3069 if (excludedPackageCount > 0) {
3070 pw.println(" Excluded packages:");
3071 for (int j = 0; j < excludedPackageCount; j++) {
3072 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
3073 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
3074 pw.print(" "); pw.print("user: "); pw.print(userId);
3075 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
3076 }
3077 }
3078 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003079 }
3080 }
John Spurlock1af30c72014-03-10 08:33:35 -04003081
3082 private static final class Restriction {
3083 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
3084 int mode;
3085 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
3086 }
Jason Monk62062992014-05-06 09:55:28 -04003087
3088 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003089 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04003090 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003091 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003092 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003093 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04003094 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07003095 if (restriction != null) {
3096 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
3097 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003098 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003099 }
3100 }
3101
3102 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08003103 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
3104 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003105 if (Binder.getCallingPid() != Process.myPid()) {
3106 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
3107 Binder.getCallingPid(), Binder.getCallingUid(), null);
3108 }
3109 if (userHandle != UserHandle.getCallingUserId()) {
3110 if (mContext.checkCallingOrSelfPermission(Manifest.permission
3111 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
3112 && mContext.checkCallingOrSelfPermission(Manifest.permission
3113 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
3114 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
3115 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04003116 }
3117 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003118 verifyIncomingOp(code);
3119 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003120 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003121 }
3122
3123 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08003124 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07003125 synchronized (AppOpsService.this) {
3126 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
3127
3128 if (restrictionState == null) {
3129 try {
3130 restrictionState = new ClientRestrictionState(token);
3131 } catch (RemoteException e) {
3132 return;
3133 }
3134 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08003135 }
Svet Ganov442ed572016-08-17 17:29:43 -07003136
3137 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003138 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07003139 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07003140 }
3141
3142 if (restrictionState.isDefault()) {
3143 mOpUserRestrictions.remove(token);
3144 restrictionState.destroy();
3145 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003146 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04003147 }
3148
Svet Ganov3a95f832018-03-23 17:44:30 -07003149 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003150 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003151 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003152 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003153 if (callbacks == null) {
3154 return;
3155 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08003156 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003157 }
3158
Svet Ganov3a95f832018-03-23 17:44:30 -07003159 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04003160 }
3161
3162 @Override
3163 public void removeUser(int userHandle) throws RemoteException {
3164 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07003165 synchronized (AppOpsService.this) {
3166 final int tokenCount = mOpUserRestrictions.size();
3167 for (int i = tokenCount - 1; i >= 0; i--) {
3168 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
3169 opRestrictions.removeUser(userHandle);
3170 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003171 removeUidsForUserLocked(userHandle);
3172 }
3173 }
3174
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003175 @Override
3176 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003177 if (Binder.getCallingUid() != uid) {
3178 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3179 != PackageManager.PERMISSION_GRANTED) {
3180 return false;
3181 }
3182 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003183 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003184 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003185 if (resolvedPackageName == null) {
3186 return false;
3187 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003188 synchronized (AppOpsService.this) {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003189 for (int i = mClients.size() - 1; i >= 0; i--) {
3190 final ClientState client = mClients.valueAt(i);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003191 for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
3192 final Op op = client.mStartedOps.get(j);
3193 if (op.op == code && op.uid == uid) return true;
3194 }
3195 }
3196 }
3197 return false;
3198 }
3199
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003200 private void removeUidsForUserLocked(int userHandle) {
3201 for (int i = mUidStates.size() - 1; i >= 0; --i) {
3202 final int uid = mUidStates.keyAt(i);
3203 if (UserHandle.getUserId(uid) == userHandle) {
3204 mUidStates.removeAt(i);
3205 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003206 }
3207 }
3208
Jason Monk62062992014-05-06 09:55:28 -04003209 private void checkSystemUid(String function) {
3210 int uid = Binder.getCallingUid();
3211 if (uid != Process.SYSTEM_UID) {
3212 throw new SecurityException(function + " must by called by the system");
3213 }
3214 }
3215
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003216 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08003217 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003218 return "root";
3219 } else if (uid == Process.SHELL_UID) {
3220 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08003221 } else if (uid == Process.MEDIA_UID) {
3222 return "media";
3223 } else if (uid == Process.AUDIOSERVER_UID) {
3224 return "audioserver";
3225 } else if (uid == Process.CAMERASERVER_UID) {
3226 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003227 } else if (uid == Process.SYSTEM_UID && packageName == null) {
3228 return "android";
3229 }
3230 return packageName;
3231 }
3232
Svet Ganov82f09bc2018-01-12 22:08:40 -08003233 private static int resolveUid(String packageName) {
3234 if (packageName == null) {
3235 return -1;
3236 }
3237 switch (packageName) {
3238 case "root":
3239 return Process.ROOT_UID;
3240 case "shell":
3241 return Process.SHELL_UID;
3242 case "media":
3243 return Process.MEDIA_UID;
3244 case "audioserver":
3245 return Process.AUDIOSERVER_UID;
3246 case "cameraserver":
3247 return Process.CAMERASERVER_UID;
3248 }
3249 return -1;
3250 }
3251
Svet Ganov2af57082015-07-30 08:44:20 -07003252 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07003253 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07003254 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08003255 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07003256 } catch (RemoteException e) {
3257 /* ignore - local call */
3258 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07003259 if (packageNames == null) {
3260 return EmptyArray.STRING;
3261 }
3262 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07003263 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003264
3265 private final class ClientRestrictionState implements DeathRecipient {
3266 private final IBinder token;
3267 SparseArray<boolean[]> perUserRestrictions;
3268 SparseArray<String[]> perUserExcludedPackages;
3269
3270 public ClientRestrictionState(IBinder token)
3271 throws RemoteException {
3272 token.linkToDeath(this, 0);
3273 this.token = token;
3274 }
3275
3276 public boolean setRestriction(int code, boolean restricted,
3277 String[] excludedPackages, int userId) {
3278 boolean changed = false;
3279
3280 if (perUserRestrictions == null && restricted) {
3281 perUserRestrictions = new SparseArray<>();
3282 }
3283
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003284 int[] users;
3285 if (userId == UserHandle.USER_ALL) {
3286 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003287
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003288 users = new int[liveUsers.size()];
3289 for (int i = 0; i < liveUsers.size(); i++) {
3290 users[i] = liveUsers.get(i).id;
3291 }
3292 } else {
3293 users = new int[]{userId};
3294 }
3295
3296 if (perUserRestrictions != null) {
3297 int numUsers = users.length;
3298
3299 for (int i = 0; i < numUsers; i++) {
3300 int thisUserId = users[i];
3301
3302 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
3303 if (userRestrictions == null && restricted) {
3304 userRestrictions = new boolean[AppOpsManager._NUM_OP];
3305 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003306 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003307 if (userRestrictions != null && userRestrictions[code] != restricted) {
3308 userRestrictions[code] = restricted;
3309 if (!restricted && isDefault(userRestrictions)) {
3310 perUserRestrictions.remove(thisUserId);
3311 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003312 }
3313 changed = true;
3314 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07003315
3316 if (userRestrictions != null) {
3317 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
3318 if (perUserExcludedPackages == null && !noExcludedPackages) {
3319 perUserExcludedPackages = new SparseArray<>();
3320 }
3321 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
3322 perUserExcludedPackages.get(thisUserId))) {
3323 if (noExcludedPackages) {
3324 perUserExcludedPackages.remove(thisUserId);
3325 if (perUserExcludedPackages.size() <= 0) {
3326 perUserExcludedPackages = null;
3327 }
3328 } else {
3329 perUserExcludedPackages.put(thisUserId, excludedPackages);
3330 }
3331 changed = true;
3332 }
3333 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003334 }
3335 }
3336
3337 return changed;
3338 }
3339
3340 public boolean hasRestriction(int restriction, String packageName, int userId) {
3341 if (perUserRestrictions == null) {
3342 return false;
3343 }
3344 boolean[] restrictions = perUserRestrictions.get(userId);
3345 if (restrictions == null) {
3346 return false;
3347 }
3348 if (!restrictions[restriction]) {
3349 return false;
3350 }
3351 if (perUserExcludedPackages == null) {
3352 return true;
3353 }
3354 String[] perUserExclusions = perUserExcludedPackages.get(userId);
3355 if (perUserExclusions == null) {
3356 return true;
3357 }
3358 return !ArrayUtils.contains(perUserExclusions, packageName);
3359 }
3360
3361 public void removeUser(int userId) {
3362 if (perUserExcludedPackages != null) {
3363 perUserExcludedPackages.remove(userId);
3364 if (perUserExcludedPackages.size() <= 0) {
3365 perUserExcludedPackages = null;
3366 }
3367 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07003368 if (perUserRestrictions != null) {
3369 perUserRestrictions.remove(userId);
3370 if (perUserRestrictions.size() <= 0) {
3371 perUserRestrictions = null;
3372 }
3373 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003374 }
3375
3376 public boolean isDefault() {
3377 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
3378 }
3379
3380 @Override
3381 public void binderDied() {
3382 synchronized (AppOpsService.this) {
3383 mOpUserRestrictions.remove(token);
3384 if (perUserRestrictions == null) {
3385 return;
3386 }
3387 final int userCount = perUserRestrictions.size();
3388 for (int i = 0; i < userCount; i++) {
3389 final boolean[] restrictions = perUserRestrictions.valueAt(i);
3390 final int restrictionCount = restrictions.length;
3391 for (int j = 0; j < restrictionCount; j++) {
3392 if (restrictions[j]) {
3393 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07003394 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003395 }
3396 }
3397 }
3398 destroy();
3399 }
3400 }
3401
3402 public void destroy() {
3403 token.unlinkToDeath(this, 0);
3404 }
3405
3406 private boolean isDefault(boolean[] array) {
3407 if (ArrayUtils.isEmpty(array)) {
3408 return true;
3409 }
3410 for (boolean value : array) {
3411 if (value) {
3412 return false;
3413 }
3414 }
3415 return true;
3416 }
3417 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003418}