blob: 7c2eea3f68aa2b7447a1e959a48ae116d1f4fb17 [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
19import java.io.File;
20import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -080021import java.io.FileInputStream;
22import java.io.FileNotFoundException;
23import java.io.FileOutputStream;
24import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080025import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010026import java.nio.charset.StandardCharsets;
Dianne Hackborn35654b62013-01-14 17:38:02 -080027import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -070028import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -070029import java.util.Collections;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080030import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -080031import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -080032import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -070033import java.util.Map;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080034
Svet Ganov9cea80cd2016-02-16 11:47:00 -080035import android.Manifest;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -080036import android.app.ActivityManager;
Jason Monk1c7c3192014-06-26 12:52:18 -040037import android.app.ActivityThread;
Svet Ganov2af57082015-07-30 08:44:20 -070038import android.app.AppGlobals;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080039import android.app.AppOpsManager;
40import android.content.Context;
Jason Monk1c7c3192014-06-26 12:52:18 -040041import android.content.pm.ApplicationInfo;
42import android.content.pm.IPackageManager;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080043import android.content.pm.PackageManager;
John Spurlock7b414672014-07-18 13:02:39 -040044import android.media.AudioAttributes;
Dianne Hackborn35654b62013-01-14 17:38:02 -080045import android.os.AsyncTask;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080046import android.os.Binder;
Jason Monk62062992014-05-06 09:55:28 -040047import android.os.Bundle;
Dianne Hackborn35654b62013-01-14 17:38:02 -080048import android.os.Handler;
Dianne Hackbornc2293022013-02-06 23:14:49 -080049import android.os.IBinder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080050import android.os.Process;
Dianne Hackbornc2293022013-02-06 23:14:49 -080051import android.os.RemoteException;
Dianne Hackborn268e4e32015-11-18 16:29:56 -080052import android.os.ResultReceiver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080053import android.os.ServiceManager;
Dianne Hackborn354736e2016-08-22 17:00:05 -070054import android.os.ShellCallback;
Dianne Hackborn268e4e32015-11-18 16:29:56 -080055import android.os.ShellCommand;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080056import android.os.UserHandle;
Svet Ganov6ee871e2015-07-10 14:29:33 -070057import android.os.storage.MountServiceInternal;
Dianne Hackborne98f5db2013-07-17 17:23:25 -070058import android.util.ArrayMap;
John Spurlock1af30c72014-03-10 08:33:35 -040059import android.util.ArraySet;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080060import android.util.AtomicFile;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -080061import android.util.Log;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080062import android.util.Slog;
63import android.util.SparseArray;
Svet Ganov2af57082015-07-30 08:44:20 -070064import android.util.SparseIntArray;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080065import android.util.TimeUtils;
Dianne Hackborn35654b62013-01-14 17:38:02 -080066import android.util.Xml;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080067
68import com.android.internal.app.IAppOpsService;
Dianne Hackbornc2293022013-02-06 23:14:49 -080069import com.android.internal.app.IAppOpsCallback;
Svet Ganov6ee871e2015-07-10 14:29:33 -070070import com.android.internal.os.Zygote;
Svet Ganov2af57082015-07-30 08:44:20 -070071import com.android.internal.util.ArrayUtils;
Dianne Hackborn35654b62013-01-14 17:38:02 -080072import com.android.internal.util.FastXmlSerializer;
Svet Ganov9cea80cd2016-02-16 11:47:00 -080073import com.android.internal.util.Preconditions;
Dianne Hackborn35654b62013-01-14 17:38:02 -080074import com.android.internal.util.XmlUtils;
75
Svet Ganov2af57082015-07-30 08:44:20 -070076import libcore.util.EmptyArray;
Dianne Hackborn35654b62013-01-14 17:38:02 -080077import org.xmlpull.v1.XmlPullParser;
78import org.xmlpull.v1.XmlPullParserException;
79import org.xmlpull.v1.XmlSerializer;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080080
81public class AppOpsService extends IAppOpsService.Stub {
82 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -080083 static final boolean DEBUG = false;
84
85 // Write at most every 30 minutes.
86 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080087
88 Context mContext;
89 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -080090 final Handler mHandler;
91
92 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -080093 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -080094 final Runnable mWriteRunner = new Runnable() {
95 public void run() {
96 synchronized (AppOpsService.this) {
97 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -080098 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -080099 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
100 @Override protected Void doInBackground(Void... params) {
101 writeState();
102 return null;
103 }
104 };
105 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
106 }
107 }
108 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800109
Svet Ganov9cea80cd2016-02-16 11:47:00 -0800110 private final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800111
Ruben Brunk29931bc2016-03-11 00:24:26 -0800112 /*
113 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800114 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700115 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400116
Svet Ganov2af57082015-07-30 08:44:20 -0700117 private static final class UidState {
118 public final int uid;
119 public ArrayMap<String, Ops> pkgOps;
120 public SparseIntArray opModes;
121
122 public UidState(int uid) {
123 this.uid = uid;
124 }
125
126 public void clear() {
127 pkgOps = null;
128 opModes = null;
129 }
130
131 public boolean isDefault() {
132 return (pkgOps == null || pkgOps.isEmpty())
133 && (opModes == null || opModes.size() <= 0);
134 }
135 }
136
Dianne Hackbornc2293022013-02-06 23:14:49 -0800137 public final static class Ops extends SparseArray<Op> {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800138 public final String packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700139 public final UidState uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400140 public final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800141
Svet Ganov2af57082015-07-30 08:44:20 -0700142 public Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800143 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700144 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400145 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800146 }
147 }
148
Dianne Hackbornc2293022013-02-06 23:14:49 -0800149 public final static class Op {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700150 public final int uid;
151 public final String packageName;
Svet Ganov99b60432015-06-27 13:15:22 -0700152 public int proxyUid = -1;
153 public String proxyPackageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800154 public final int op;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800155 public int mode;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800156 public int duration;
157 public long time;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800158 public long rejectTime;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800159 public int nesting;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800160
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700161 public Op(int _uid, String _packageName, int _op) {
162 uid = _uid;
163 packageName = _packageName;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800164 op = _op;
David Braunf5d83192013-09-16 13:43:51 -0700165 mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800166 }
167 }
168
Dianne Hackbornc2293022013-02-06 23:14:49 -0800169 final SparseArray<ArrayList<Callback>> mOpModeWatchers
170 = new SparseArray<ArrayList<Callback>>();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700171 final ArrayMap<String, ArrayList<Callback>> mPackageModeWatchers
172 = new ArrayMap<String, ArrayList<Callback>>();
173 final ArrayMap<IBinder, Callback> mModeWatchers
174 = new ArrayMap<IBinder, Callback>();
John Spurlock1af30c72014-03-10 08:33:35 -0400175 final SparseArray<SparseArray<Restriction>> mAudioRestrictions
176 = new SparseArray<SparseArray<Restriction>>();
Dianne Hackbornc2293022013-02-06 23:14:49 -0800177
178 public final class Callback implements DeathRecipient {
179 final IAppOpsCallback mCallback;
180
181 public Callback(IAppOpsCallback callback) {
182 mCallback = callback;
183 try {
184 mCallback.asBinder().linkToDeath(this, 0);
185 } catch (RemoteException e) {
186 }
187 }
188
189 public void unlinkToDeath() {
190 mCallback.asBinder().unlinkToDeath(this, 0);
191 }
192
193 @Override
194 public void binderDied() {
195 stopWatchingMode(mCallback);
196 }
197 }
198
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700199 final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<IBinder, ClientState>();
200
201 public final class ClientState extends Binder implements DeathRecipient {
202 final IBinder mAppToken;
203 final int mPid;
204 final ArrayList<Op> mStartedOps;
205
206 public ClientState(IBinder appToken) {
207 mAppToken = appToken;
208 mPid = Binder.getCallingPid();
209 if (appToken instanceof Binder) {
210 // For local clients, there is no reason to track them.
211 mStartedOps = null;
212 } else {
213 mStartedOps = new ArrayList<Op>();
214 try {
215 mAppToken.linkToDeath(this, 0);
216 } catch (RemoteException e) {
217 }
218 }
219 }
220
221 @Override
222 public String toString() {
223 return "ClientState{" +
224 "mAppToken=" + mAppToken +
225 ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") +
226 '}';
227 }
228
229 @Override
230 public void binderDied() {
231 synchronized (AppOpsService.this) {
232 for (int i=mStartedOps.size()-1; i>=0; i--) {
233 finishOperationLocked(mStartedOps.get(i));
234 }
235 mClients.remove(mAppToken);
236 }
237 }
238 }
239
Jeff Brown6f357d32014-01-15 20:40:55 -0800240 public AppOpsService(File storagePath, Handler handler) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800241 mFile = new AtomicFile(storagePath);
Jeff Brown6f357d32014-01-15 20:40:55 -0800242 mHandler = handler;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800243 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800244 }
David Braunf5d83192013-09-16 13:43:51 -0700245
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800246 public void publish(Context context) {
247 mContext = context;
248 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
249 }
250
Dianne Hackborn514074f2013-02-11 10:52:46 -0800251 public void systemReady() {
252 synchronized (this) {
253 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700254 for (int i = mUidStates.size() - 1; i >= 0; i--) {
255 UidState uidState = mUidStates.valueAt(i);
256
257 String[] packageNames = getPackagesForUid(uidState.uid);
258 if (ArrayUtils.isEmpty(packageNames)) {
259 uidState.clear();
260 mUidStates.removeAt(i);
261 changed = true;
262 continue;
263 }
264
265 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
266 if (pkgs == null) {
267 continue;
268 }
269
Dianne Hackborn514074f2013-02-11 10:52:46 -0800270 Iterator<Ops> it = pkgs.values().iterator();
271 while (it.hasNext()) {
272 Ops ops = it.next();
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700273 int curUid = -1;
Dianne Hackborn514074f2013-02-11 10:52:46 -0800274 try {
Jeff Sharkeycd654482016-01-08 17:42:11 -0700275 curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
276 PackageManager.MATCH_UNINSTALLED_PACKAGES,
Svet Ganov2af57082015-07-30 08:44:20 -0700277 UserHandle.getUserId(ops.uidState.uid));
Jeff Sharkeye2ed23e2015-10-29 19:00:44 -0700278 } catch (RemoteException ignored) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800279 }
Svet Ganov2af57082015-07-30 08:44:20 -0700280 if (curUid != ops.uidState.uid) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800281 Slog.i(TAG, "Pruning old package " + ops.packageName
Svet Ganov2af57082015-07-30 08:44:20 -0700282 + "/" + ops.uidState + ": new uid=" + curUid);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800283 it.remove();
284 changed = true;
285 }
286 }
Svet Ganov2af57082015-07-30 08:44:20 -0700287
288 if (uidState.isDefault()) {
289 mUidStates.removeAt(i);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800290 }
291 }
292 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800293 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800294 }
295 }
Svet Ganov6ee871e2015-07-10 14:29:33 -0700296
297 MountServiceInternal mountServiceInternal = LocalServices.getService(
298 MountServiceInternal.class);
299 mountServiceInternal.addExternalStoragePolicy(
300 new MountServiceInternal.ExternalStorageMountPolicy() {
301 @Override
302 public int getMountMode(int uid, String packageName) {
303 if (Process.isIsolated(uid)) {
304 return Zygote.MOUNT_EXTERNAL_NONE;
305 }
306 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
307 packageName) != AppOpsManager.MODE_ALLOWED) {
308 return Zygote.MOUNT_EXTERNAL_NONE;
309 }
310 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
311 packageName) != AppOpsManager.MODE_ALLOWED) {
312 return Zygote.MOUNT_EXTERNAL_READ;
313 }
314 return Zygote.MOUNT_EXTERNAL_WRITE;
315 }
316
317 @Override
318 public boolean hasExternalStorage(int uid, String packageName) {
319 final int mountMode = getMountMode(uid, packageName);
320 return mountMode == Zygote.MOUNT_EXTERNAL_READ
321 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
322 }
323 });
Dianne Hackborn514074f2013-02-11 10:52:46 -0800324 }
325
326 public void packageRemoved(int uid, String packageName) {
327 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700328 UidState uidState = mUidStates.get(uid);
329 if (uidState == null) {
330 return;
331 }
332
333 boolean changed = false;
334
335 // Remove any package state if such.
336 if (uidState.pkgOps != null && uidState.pkgOps.remove(packageName) != null) {
337 changed = true;
338 }
339
340 // If we just nuked the last package state check if the UID is valid.
341 if (changed && uidState.pkgOps.isEmpty()
342 && getPackagesForUid(uid).length <= 0) {
343 mUidStates.remove(uid);
344 }
345
346 if (changed) {
347 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800348 }
349 }
350 }
351
352 public void uidRemoved(int uid) {
353 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700354 if (mUidStates.indexOfKey(uid) >= 0) {
355 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800356 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -0800357 }
358 }
359 }
360
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800361 public void shutdown() {
362 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -0800363 boolean doWrite = false;
364 synchronized (this) {
365 if (mWriteScheduled) {
366 mWriteScheduled = false;
367 doWrite = true;
368 }
369 }
370 if (doWrite) {
371 writeState();
372 }
373 }
374
Dianne Hackborn72e39832013-01-18 18:36:09 -0800375 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
376 ArrayList<AppOpsManager.OpEntry> resOps = null;
377 if (ops == null) {
378 resOps = new ArrayList<AppOpsManager.OpEntry>();
379 for (int j=0; j<pkgOps.size(); j++) {
380 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800381 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Svet Ganov99b60432015-06-27 13:15:22 -0700382 curOp.rejectTime, curOp.duration, curOp.proxyUid,
383 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800384 }
385 } else {
386 for (int j=0; j<ops.length; j++) {
387 Op curOp = pkgOps.get(ops[j]);
388 if (curOp != null) {
389 if (resOps == null) {
390 resOps = new ArrayList<AppOpsManager.OpEntry>();
391 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800392 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
Svet Ganov99b60432015-06-27 13:15:22 -0700393 curOp.rejectTime, curOp.duration, curOp.proxyUid,
394 curOp.proxyPackageName));
Dianne Hackborn72e39832013-01-18 18:36:09 -0800395 }
396 }
397 }
398 return resOps;
399 }
400
Dianne Hackborn35654b62013-01-14 17:38:02 -0800401 @Override
402 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
403 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
404 Binder.getCallingPid(), Binder.getCallingUid(), null);
405 ArrayList<AppOpsManager.PackageOps> res = null;
406 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700407 final int uidStateCount = mUidStates.size();
408 for (int i = 0; i < uidStateCount; i++) {
409 UidState uidState = mUidStates.valueAt(i);
410 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
411 continue;
412 }
413 ArrayMap<String, Ops> packages = uidState.pkgOps;
414 final int packageCount = packages.size();
415 for (int j = 0; j < packageCount; j++) {
416 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800417 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800418 if (resOps != null) {
419 if (res == null) {
420 res = new ArrayList<AppOpsManager.PackageOps>();
421 }
422 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700423 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800424 res.add(resPackage);
425 }
426 }
427 }
428 }
429 return res;
430 }
431
432 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -0800433 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
434 int[] ops) {
435 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
436 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000437 String resolvedPackageName = resolvePackageName(uid, packageName);
438 if (resolvedPackageName == null) {
439 return Collections.emptyList();
440 }
Dianne Hackborn72e39832013-01-18 18:36:09 -0800441 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000442 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800443 if (pkgOps == null) {
444 return null;
445 }
446 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
447 if (resOps == null) {
448 return null;
449 }
450 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
451 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -0700452 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -0800453 res.add(resPackage);
454 return res;
455 }
456 }
457
Dianne Hackborn607b4142013-08-02 18:10:10 -0700458 private void pruneOp(Op op, int uid, String packageName) {
459 if (op.time == 0 && op.rejectTime == 0) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000460 Ops ops = getOpsRawLocked(uid, packageName, false);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700461 if (ops != null) {
462 ops.remove(op.op);
463 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -0700464 UidState uidState = ops.uidState;
465 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700466 if (pkgOps != null) {
467 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700468 if (pkgOps.isEmpty()) {
469 uidState.pkgOps = null;
470 }
471 if (uidState.isDefault()) {
472 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700473 }
474 }
475 }
476 }
477 }
478 }
479
Dianne Hackborn72e39832013-01-18 18:36:09 -0800480 @Override
Svet Ganov2af57082015-07-30 08:44:20 -0700481 public void setUidMode(int code, int uid, int mode) {
482 if (Binder.getCallingPid() != Process.myPid()) {
483 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
484 Binder.getCallingPid(), Binder.getCallingUid(), null);
485 }
486 verifyIncomingOp(code);
487 code = AppOpsManager.opToSwitch(code);
488
489 synchronized (this) {
490 final int defaultMode = AppOpsManager.opToDefaultMode(code);
491
492 UidState uidState = getUidStateLocked(uid, false);
493 if (uidState == null) {
494 if (mode == defaultMode) {
495 return;
496 }
497 uidState = new UidState(uid);
498 uidState.opModes = new SparseIntArray();
499 uidState.opModes.put(code, mode);
500 mUidStates.put(uid, uidState);
501 scheduleWriteLocked();
502 } else if (uidState.opModes == null) {
503 if (mode != defaultMode) {
504 uidState.opModes = new SparseIntArray();
505 uidState.opModes.put(code, mode);
506 scheduleWriteLocked();
507 }
508 } else {
509 if (uidState.opModes.get(code) == mode) {
510 return;
511 }
512 if (mode == defaultMode) {
513 uidState.opModes.delete(code);
514 if (uidState.opModes.size() <= 0) {
515 uidState.opModes = null;
516 }
517 } else {
518 uidState.opModes.put(code, mode);
519 }
520 scheduleWriteLocked();
521 }
522 }
523
Svetoslav215b44a2015-08-04 19:03:40 -0700524 String[] uidPackageNames = getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -0700525 ArrayMap<Callback, ArraySet<String>> callbackSpecs = null;
526
riddle_hsu40b300f2015-11-23 13:22:03 +0800527 synchronized (this) {
528 ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -0700529 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -0700530 final int callbackCount = callbacks.size();
531 for (int i = 0; i < callbackCount; i++) {
532 Callback callback = callbacks.get(i);
riddle_hsu40b300f2015-11-23 13:22:03 +0800533 ArraySet<String> changedPackages = new ArraySet<>();
534 Collections.addAll(changedPackages, uidPackageNames);
535 callbackSpecs = new ArrayMap<>();
536 callbackSpecs.put(callback, changedPackages);
537 }
538 }
539
540 for (String uidPackageName : uidPackageNames) {
541 callbacks = mPackageModeWatchers.get(uidPackageName);
542 if (callbacks != null) {
543 if (callbackSpecs == null) {
544 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -0700545 }
riddle_hsu40b300f2015-11-23 13:22:03 +0800546 final int callbackCount = callbacks.size();
547 for (int i = 0; i < callbackCount; i++) {
548 Callback callback = callbacks.get(i);
549 ArraySet<String> changedPackages = callbackSpecs.get(callback);
550 if (changedPackages == null) {
551 changedPackages = new ArraySet<>();
552 callbackSpecs.put(callback, changedPackages);
553 }
554 changedPackages.add(uidPackageName);
555 }
Svet Ganov2af57082015-07-30 08:44:20 -0700556 }
557 }
558 }
559
560 if (callbackSpecs == null) {
561 return;
562 }
563
564 // There are components watching for mode changes such as window manager
565 // and location manager which are in our process. The callbacks in these
566 // components may require permissions our remote caller does not have.
567 final long identity = Binder.clearCallingIdentity();
568 try {
569 for (int i = 0; i < callbackSpecs.size(); i++) {
570 Callback callback = callbackSpecs.keyAt(i);
571 ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
572 try {
573 if (reportedPackageNames == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700574 callback.mCallback.opChanged(code, uid, null);
Svet Ganov2af57082015-07-30 08:44:20 -0700575 } else {
576 final int reportedPackageCount = reportedPackageNames.size();
577 for (int j = 0; j < reportedPackageCount; j++) {
578 String reportedPackageName = reportedPackageNames.valueAt(j);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700579 callback.mCallback.opChanged(code, uid, reportedPackageName);
Svet Ganov2af57082015-07-30 08:44:20 -0700580 }
581 }
582 } catch (RemoteException e) {
583 Log.w(TAG, "Error dispatching op op change", e);
584 }
585 }
586 } finally {
587 Binder.restoreCallingIdentity(identity);
588 }
589 }
590
591 @Override
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800592 public void setMode(int code, int uid, String packageName, int mode) {
Dianne Hackbornb64afe12014-07-22 16:29:04 -0700593 if (Binder.getCallingPid() != Process.myPid()) {
594 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
595 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborn133b9df2014-07-01 13:06:10 -0700596 }
Dianne Hackborn961321f2013-02-05 17:22:41 -0800597 verifyIncomingOp(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800598 ArrayList<Callback> repCbs = null;
599 code = AppOpsManager.opToSwitch(code);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800600 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700601 UidState uidState = getUidStateLocked(uid, false);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800602 Op op = getOpLocked(code, uid, packageName, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800603 if (op != null) {
604 if (op.mode != mode) {
605 op.mode = mode;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800606 ArrayList<Callback> cbs = mOpModeWatchers.get(code);
607 if (cbs != null) {
608 if (repCbs == null) {
609 repCbs = new ArrayList<Callback>();
610 }
611 repCbs.addAll(cbs);
612 }
613 cbs = mPackageModeWatchers.get(packageName);
614 if (cbs != null) {
615 if (repCbs == null) {
616 repCbs = new ArrayList<Callback>();
617 }
618 repCbs.addAll(cbs);
619 }
David Braunf5d83192013-09-16 13:43:51 -0700620 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -0800621 // If going into the default mode, prune this op
622 // if there is nothing else interesting in it.
Dianne Hackborn607b4142013-08-02 18:10:10 -0700623 pruneOp(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -0800624 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800625 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800626 }
627 }
628 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800629 if (repCbs != null) {
Svet Ganov38536112015-05-19 12:45:52 -0700630 // There are components watching for mode changes such as window manager
631 // and location manager which are in our process. The callbacks in these
632 // components may require permissions our remote caller does not have.
633 final long identity = Binder.clearCallingIdentity();
634 try {
635 for (int i = 0; i < repCbs.size(); i++) {
636 try {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700637 repCbs.get(i).mCallback.opChanged(code, uid, packageName);
Svet Ganov38536112015-05-19 12:45:52 -0700638 } catch (RemoteException e) {
639 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800640 }
Svet Ganov38536112015-05-19 12:45:52 -0700641 } finally {
642 Binder.restoreCallingIdentity(identity);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800643 }
644 }
645 }
646
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700647 private static HashMap<Callback, ArrayList<ChangeRec>> addCallbacks(
648 HashMap<Callback, ArrayList<ChangeRec>> callbacks,
649 int op, int uid, String packageName, ArrayList<Callback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700650 if (cbs == null) {
651 return callbacks;
652 }
653 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700654 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700655 }
Svet Ganov2af57082015-07-30 08:44:20 -0700656 boolean duplicate = false;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700657 for (int i=0; i<cbs.size(); i++) {
658 Callback cb = cbs.get(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700659 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700660 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700661 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700662 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -0700663 } else {
664 final int reportCount = reports.size();
665 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700666 ChangeRec report = reports.get(j);
667 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -0700668 duplicate = true;
669 break;
670 }
671 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700672 }
Svet Ganov2af57082015-07-30 08:44:20 -0700673 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700674 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -0700675 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700676 }
677 return callbacks;
678 }
679
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700680 static final class ChangeRec {
681 final int op;
682 final int uid;
683 final String pkg;
684
685 ChangeRec(int _op, int _uid, String _pkg) {
686 op = _op;
687 uid = _uid;
688 pkg = _pkg;
689 }
690 }
691
Dianne Hackborn607b4142013-08-02 18:10:10 -0700692 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800693 public void resetAllModes(int reqUserId, String reqPackageName) {
694 final int callingPid = Binder.getCallingPid();
695 final int callingUid = Binder.getCallingUid();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700696 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800697 callingPid, callingUid, null);
698 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
699 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -0700700
701 int reqUid = -1;
702 if (reqPackageName != null) {
703 try {
704 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -0700705 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -0700706 } catch (RemoteException e) {
707 /* ignore - local call */
708 }
709 }
710
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700711 HashMap<Callback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700712 synchronized (this) {
713 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -0700714 for (int i = mUidStates.size() - 1; i >= 0; i--) {
715 UidState uidState = mUidStates.valueAt(i);
716
717 SparseIntArray opModes = uidState.opModes;
718 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
719 final int uidOpCount = opModes.size();
720 for (int j = uidOpCount - 1; j >= 0; j--) {
721 final int code = opModes.keyAt(j);
722 if (AppOpsManager.opAllowsReset(code)) {
723 opModes.removeAt(j);
724 if (opModes.size() <= 0) {
725 uidState.opModes = null;
726 }
727 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700728 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -0700729 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700730 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -0700731 mPackageModeWatchers.get(packageName));
732 }
733 }
734 }
735 }
736
737 if (uidState.pkgOps == null) {
738 continue;
739 }
740
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800741 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -0700742 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +0100743 // Skip any ops for a different user
744 continue;
745 }
Svet Ganov2af57082015-07-30 08:44:20 -0700746
747 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700748 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
749 while (it.hasNext()) {
750 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700751 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800752 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
753 // Skip any ops for a different package
754 continue;
755 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700756 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700757 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700758 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -0700759 if (AppOpsManager.opAllowsReset(curOp.op)
760 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -0700761 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700762 changed = true;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700763 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -0700764 mOpModeWatchers.get(curOp.op));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700765 callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -0700766 mPackageModeWatchers.get(packageName));
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700767 if (curOp.time == 0 && curOp.rejectTime == 0) {
768 pkgOps.removeAt(j);
769 }
Dianne Hackborn607b4142013-08-02 18:10:10 -0700770 }
771 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -0700772 if (pkgOps.size() == 0) {
773 it.remove();
774 }
775 }
Svet Ganov2af57082015-07-30 08:44:20 -0700776 if (uidState.isDefault()) {
777 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700778 }
779 }
Svet Ganov2af57082015-07-30 08:44:20 -0700780
Dianne Hackborn607b4142013-08-02 18:10:10 -0700781 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800782 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700783 }
784 }
785 if (callbacks != null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700786 for (Map.Entry<Callback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
Dianne Hackborn607b4142013-08-02 18:10:10 -0700787 Callback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700788 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -0700789 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700790 ChangeRec rep = reports.get(i);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700791 try {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700792 cb.mCallback.opChanged(rep.op, rep.uid, rep.pkg);
Dianne Hackborn607b4142013-08-02 18:10:10 -0700793 } catch (RemoteException e) {
794 }
795 }
796 }
797 }
798 }
799
Dianne Hackbornc2293022013-02-06 23:14:49 -0800800 @Override
801 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -0800802 if (callback == null) {
803 return;
804 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800805 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -0700806 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800807 Callback cb = mModeWatchers.get(callback.asBinder());
808 if (cb == null) {
809 cb = new Callback(callback);
810 mModeWatchers.put(callback.asBinder(), cb);
811 }
812 if (op != AppOpsManager.OP_NONE) {
813 ArrayList<Callback> cbs = mOpModeWatchers.get(op);
814 if (cbs == null) {
815 cbs = new ArrayList<Callback>();
816 mOpModeWatchers.put(op, cbs);
817 }
818 cbs.add(cb);
819 }
820 if (packageName != null) {
821 ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName);
822 if (cbs == null) {
823 cbs = new ArrayList<Callback>();
824 mPackageModeWatchers.put(packageName, cbs);
825 }
826 cbs.add(cb);
827 }
828 }
829 }
830
831 @Override
832 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -0800833 if (callback == null) {
834 return;
835 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800836 synchronized (this) {
837 Callback cb = mModeWatchers.remove(callback.asBinder());
838 if (cb != null) {
839 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700840 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800841 ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
842 cbs.remove(cb);
843 if (cbs.size() <= 0) {
844 mOpModeWatchers.removeAt(i);
845 }
846 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700847 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
848 ArrayList<Callback> cbs = mPackageModeWatchers.valueAt(i);
849 cbs.remove(cb);
850 if (cbs.size() <= 0) {
851 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800852 }
853 }
854 }
855 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800856 }
857
858 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700859 public IBinder getToken(IBinder clientToken) {
860 synchronized (this) {
861 ClientState cs = mClients.get(clientToken);
862 if (cs == null) {
863 cs = new ClientState(clientToken);
864 mClients.put(clientToken, cs);
865 }
866 return cs;
867 }
868 }
869
870 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -0800871 public int checkOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800872 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -0800873 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000874 String resolvedPackageName = resolvePackageName(uid, packageName);
875 if (resolvedPackageName == null) {
876 return AppOpsManager.MODE_IGNORED;
877 }
Dianne Hackborn35654b62013-01-14 17:38:02 -0800878 synchronized (this) {
Svet Ganov442ed572016-08-17 17:29:43 -0700879 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -0400880 return AppOpsManager.MODE_IGNORED;
881 }
Svet Ganov2af57082015-07-30 08:44:20 -0700882 code = AppOpsManager.opToSwitch(code);
883 UidState uidState = getUidStateLocked(uid, false);
884 if (uidState != null && uidState.opModes != null) {
885 final int uidMode = uidState.opModes.get(code);
886 if (uidMode != AppOpsManager.MODE_ALLOWED) {
887 return uidMode;
888 }
889 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000890 Op op = getOpLocked(code, uid, resolvedPackageName, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800891 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -0700892 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -0800893 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800894 return op.mode;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800895 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800896 }
897
898 @Override
John Spurlock7b414672014-07-18 13:02:39 -0400899 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +0000900 boolean suspended;
901 try {
902 suspended = isPackageSuspendedForUser(packageName, uid);
903 } catch (IllegalArgumentException ex) {
904 // Package not found.
905 suspended = false;
906 }
907
908 if (suspended) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000909 Log.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid);
910 return AppOpsManager.MODE_IGNORED;
911 }
912
John Spurlock1af30c72014-03-10 08:33:35 -0400913 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -0400914 final int mode = checkRestrictionLocked(code, usage, uid, packageName);
John Spurlock1af30c72014-03-10 08:33:35 -0400915 if (mode != AppOpsManager.MODE_ALLOWED) {
916 return mode;
917 }
918 }
919 return checkOperation(code, uid, packageName);
920 }
921
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000922 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000923 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000924 return AppGlobals.getPackageManager().isPackageSuspendedForUser(
925 pkg, UserHandle.getUserId(uid));
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000926 } catch (RemoteException re) {
927 throw new SecurityException("Could not talk to package manager service");
928 }
Andrei Stingaceanu2bc2feb2016-02-11 16:23:49 +0000929 }
930
John Spurlock7b414672014-07-18 13:02:39 -0400931 private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
932 final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
933 if (usageRestrictions != null) {
934 final Restriction r = usageRestrictions.get(usage);
John Spurlock1af30c72014-03-10 08:33:35 -0400935 if (r != null && !r.exceptionPackages.contains(packageName)) {
936 return r.mode;
937 }
938 }
939 return AppOpsManager.MODE_ALLOWED;
940 }
941
942 @Override
John Spurlock7b414672014-07-18 13:02:39 -0400943 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -0400944 String[] exceptionPackages) {
945 verifyIncomingUid(uid);
946 verifyIncomingOp(code);
947 synchronized (this) {
John Spurlock7b414672014-07-18 13:02:39 -0400948 SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
949 if (usageRestrictions == null) {
950 usageRestrictions = new SparseArray<Restriction>();
951 mAudioRestrictions.put(code, usageRestrictions);
John Spurlock1af30c72014-03-10 08:33:35 -0400952 }
John Spurlock7b414672014-07-18 13:02:39 -0400953 usageRestrictions.remove(usage);
John Spurlock1af30c72014-03-10 08:33:35 -0400954 if (mode != AppOpsManager.MODE_ALLOWED) {
955 final Restriction r = new Restriction();
956 r.mode = mode;
957 if (exceptionPackages != null) {
958 final int N = exceptionPackages.length;
959 r.exceptionPackages = new ArraySet<String>(N);
960 for (int i = 0; i < N; i++) {
961 final String pkg = exceptionPackages[i];
962 if (pkg != null) {
963 r.exceptionPackages.add(pkg.trim());
964 }
965 }
966 }
John Spurlock7b414672014-07-18 13:02:39 -0400967 usageRestrictions.put(usage, r);
John Spurlock1af30c72014-03-10 08:33:35 -0400968 }
969 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -0400970 notifyWatchersOfChange(code);
John Spurlock1af30c72014-03-10 08:33:35 -0400971 }
972
973 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -0700974 public int checkPackage(int uid, String packageName) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000975 Preconditions.checkNotNull(packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -0700976 synchronized (this) {
Dianne Hackborn0fcef842014-09-12 15:38:33 -0700977 if (getOpsRawLocked(uid, packageName, true) != null) {
Jeff Sharkey911d7f42013-09-05 18:11:45 -0700978 return AppOpsManager.MODE_ALLOWED;
979 } else {
980 return AppOpsManager.MODE_ERRORED;
981 }
982 }
983 }
984
985 @Override
Svet Ganov99b60432015-06-27 13:15:22 -0700986 public int noteProxyOperation(int code, String proxyPackageName,
987 int proxiedUid, String proxiedPackageName) {
988 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000989 final int proxyUid = Binder.getCallingUid();
990 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
991 if (resolveProxyPackageName == null) {
992 return AppOpsManager.MODE_IGNORED;
993 }
994 final int proxyMode = noteOperationUnchecked(code, proxyUid,
995 resolveProxyPackageName, -1, null);
Svet Ganov99b60432015-06-27 13:15:22 -0700996 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
997 return proxyMode;
998 }
Svetoslav Ganovf73adb62016-03-29 01:07:06 +0000999 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
1000 if (resolveProxiedPackageName == null) {
1001 return AppOpsManager.MODE_IGNORED;
1002 }
1003 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
1004 proxyMode, resolveProxyPackageName);
Svet Ganov99b60432015-06-27 13:15:22 -07001005 }
1006
1007 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001008 public int noteOperation(int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001009 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001010 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001011 String resolvedPackageName = resolvePackageName(uid, packageName);
1012 if (resolvedPackageName == null) {
1013 return AppOpsManager.MODE_IGNORED;
1014 }
1015 return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
Svet Ganov99b60432015-06-27 13:15:22 -07001016 }
1017
1018 private int noteOperationUnchecked(int code, int uid, String packageName,
1019 int proxyUid, String proxyPackageName) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001020 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001021 Ops ops = getOpsRawLocked(uid, packageName, true);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001022 if (ops == null) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001023 if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
1024 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001025 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001026 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001027 Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001028 if (isOpRestrictedLocked(uid, code, packageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001029 return AppOpsManager.MODE_IGNORED;
1030 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001031 if (op.duration == -1) {
1032 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
1033 + " code " + code + " time=" + op.time + " duration=" + op.duration);
1034 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001035 op.duration = 0;
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001036 final int switchCode = AppOpsManager.opToSwitch(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001037 UidState uidState = ops.uidState;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001038 // If there is a non-default per UID policy (we set UID op mode only if
1039 // non-default) it takes over, otherwise use the per package policy.
1040 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001041 final int uidMode = uidState.opModes.get(switchCode);
1042 if (uidMode != AppOpsManager.MODE_ALLOWED) {
1043 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1044 + switchCode + " (" + code + ") uid " + uid + " package "
1045 + packageName);
1046 op.rejectTime = System.currentTimeMillis();
1047 return uidMode;
1048 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07001049 } else {
1050 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1051 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1052 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1053 + switchCode + " (" + code + ") uid " + uid + " package "
1054 + packageName);
1055 op.rejectTime = System.currentTimeMillis();
1056 return switchOp.mode;
1057 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001058 }
1059 if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
1060 + " package " + packageName);
1061 op.time = System.currentTimeMillis();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001062 op.rejectTime = 0;
Svet Ganov99b60432015-06-27 13:15:22 -07001063 op.proxyUid = proxyUid;
1064 op.proxyPackageName = proxyPackageName;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001065 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001066 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001067 }
1068
1069 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001070 public int startOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001071 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001072 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001073 String resolvedPackageName = resolvePackageName(uid, packageName);
1074 if (resolvedPackageName == null) {
1075 return AppOpsManager.MODE_IGNORED;
1076 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001077 ClientState client = (ClientState)token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001078 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001079 Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001080 if (ops == null) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001081 if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001082 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07001083 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001084 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001085 Op op = getOpLocked(ops, code, true);
Svet Ganov442ed572016-08-17 17:29:43 -07001086 if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
Jason Monk62062992014-05-06 09:55:28 -04001087 return AppOpsManager.MODE_IGNORED;
1088 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001089 final int switchCode = AppOpsManager.opToSwitch(code);
Svet Ganov2af57082015-07-30 08:44:20 -07001090 UidState uidState = ops.uidState;
1091 if (uidState.opModes != null) {
1092 final int uidMode = uidState.opModes.get(switchCode);
1093 if (uidMode != AppOpsManager.MODE_ALLOWED) {
1094 if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
1095 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001096 + resolvedPackageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001097 op.rejectTime = System.currentTimeMillis();
1098 return uidMode;
1099 }
1100 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001101 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
1102 if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
1103 if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001104 + switchCode + " (" + code + ") uid " + uid + " package "
1105 + resolvedPackageName);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001106 op.rejectTime = System.currentTimeMillis();
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001107 return switchOp.mode;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001108 }
1109 if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001110 + " package " + resolvedPackageName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001111 if (op.nesting == 0) {
1112 op.time = System.currentTimeMillis();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001113 op.rejectTime = 0;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001114 op.duration = -1;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001115 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001116 op.nesting++;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001117 if (client.mStartedOps != null) {
1118 client.mStartedOps.add(op);
1119 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001120 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001121 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001122 }
1123
1124 @Override
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001125 public void finishOperation(IBinder token, int code, int uid, String packageName) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001126 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08001127 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001128 String resolvedPackageName = resolvePackageName(uid, packageName);
1129 if (resolvedPackageName == null) {
1130 return;
1131 }
1132 if (!(token instanceof ClientState)) {
1133 return;
1134 }
1135 ClientState client = (ClientState) token;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001136 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001137 Op op = getOpLocked(code, uid, resolvedPackageName, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001138 if (op == null) {
1139 return;
1140 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001141 if (client.mStartedOps != null) {
1142 if (!client.mStartedOps.remove(op)) {
1143 throw new IllegalStateException("Operation not started: uid" + op.uid
1144 + " pkg=" + op.packageName + " op=" + op.op);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001145 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001146 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001147 finishOperationLocked(op);
1148 }
1149 }
1150
Svet Ganovb9d71a62015-04-30 10:38:13 -07001151 @Override
1152 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001153 if (permission == null) {
1154 return AppOpsManager.OP_NONE;
1155 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07001156 return AppOpsManager.permissionToOpCode(permission);
1157 }
1158
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001159 void finishOperationLocked(Op op) {
1160 if (op.nesting <= 1) {
1161 if (op.nesting == 1) {
1162 op.duration = (int)(System.currentTimeMillis() - op.time);
1163 op.time += op.duration;
1164 } else {
1165 Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
1166 + op.packageName + " code " + op.op + " time=" + op.time
1167 + " duration=" + op.duration + " nesting=" + op.nesting);
1168 }
1169 op.nesting = 0;
1170 } else {
1171 op.nesting--;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001172 }
1173 }
1174
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001175 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001176 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001177 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001178 }
1179 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001180 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001181 }
1182 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
1183 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001184 }
1185
Dianne Hackborn961321f2013-02-05 17:22:41 -08001186 private void verifyIncomingOp(int op) {
1187 if (op >= 0 && op < AppOpsManager._NUM_OP) {
1188 return;
1189 }
1190 throw new IllegalArgumentException("Bad operation #" + op);
1191 }
1192
Svet Ganov2af57082015-07-30 08:44:20 -07001193 private UidState getUidStateLocked(int uid, boolean edit) {
1194 UidState uidState = mUidStates.get(uid);
1195 if (uidState == null) {
1196 if (!edit) {
1197 return null;
1198 }
1199 uidState = new UidState(uid);
1200 mUidStates.put(uid, uidState);
1201 }
1202 return uidState;
1203 }
1204
Dianne Hackborn0fcef842014-09-12 15:38:33 -07001205 private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07001206 UidState uidState = getUidStateLocked(uid, edit);
1207 if (uidState == null) {
1208 return null;
1209 }
1210
1211 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001212 if (!edit) {
1213 return null;
1214 }
Svet Ganov2af57082015-07-30 08:44:20 -07001215 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001216 }
Svet Ganov2af57082015-07-30 08:44:20 -07001217
1218 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001219 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001220 if (!edit) {
1221 return null;
1222 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001223 boolean isPrivileged = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001224 // This is the first time we have seen this package name under this uid,
1225 // so let's make sure it is valid.
Dianne Hackborn514074f2013-02-11 10:52:46 -08001226 if (uid != 0) {
1227 final long ident = Binder.clearCallingIdentity();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001228 try {
Dianne Hackborn514074f2013-02-11 10:52:46 -08001229 int pkgUid = -1;
1230 try {
Jason Monk1c7c3192014-06-26 12:52:18 -04001231 ApplicationInfo appInfo = ActivityThread.getPackageManager()
Jeff Sharkeycd654482016-01-08 17:42:11 -07001232 .getApplicationInfo(packageName,
1233 PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1234 UserHandle.getUserId(uid));
Jason Monk1c7c3192014-06-26 12:52:18 -04001235 if (appInfo != null) {
1236 pkgUid = appInfo.uid;
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001237 isPrivileged = (appInfo.privateFlags
1238 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001239 } else {
1240 if ("media".equals(packageName)) {
1241 pkgUid = Process.MEDIA_UID;
1242 isPrivileged = false;
Andy Hunged0ea402015-10-30 14:11:46 -07001243 } else if ("audioserver".equals(packageName)) {
1244 pkgUid = Process.AUDIOSERVER_UID;
1245 isPrivileged = false;
Chien-Yu Chen75cade02016-01-11 10:56:21 -08001246 } else if ("cameraserver".equals(packageName)) {
1247 pkgUid = Process.CAMERASERVER_UID;
1248 isPrivileged = false;
Jason Monk1c7c3192014-06-26 12:52:18 -04001249 }
Dianne Hackborn713df152013-05-17 11:27:57 -07001250 }
Jason Monk1c7c3192014-06-26 12:52:18 -04001251 } catch (RemoteException e) {
1252 Slog.w(TAG, "Could not contact PackageManager", e);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001253 }
1254 if (pkgUid != uid) {
1255 // Oops! The package name is not valid for the uid they are calling
1256 // under. Abort.
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001257 RuntimeException ex = new RuntimeException("here");
1258 ex.fillInStackTrace();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001259 Slog.w(TAG, "Bad call: specified package " + packageName
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001260 + " under uid " + uid + " but it is really " + pkgUid, ex);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001261 return null;
1262 }
1263 } finally {
1264 Binder.restoreCallingIdentity(ident);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001265 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001266 }
Svet Ganov2af57082015-07-30 08:44:20 -07001267 ops = new Ops(packageName, uidState, isPrivileged);
1268 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001269 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001270 return ops;
1271 }
1272
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001273 private void scheduleWriteLocked() {
1274 if (!mWriteScheduled) {
1275 mWriteScheduled = true;
1276 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
1277 }
1278 }
1279
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001280 private void scheduleFastWriteLocked() {
1281 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001282 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001283 mFastWriteScheduled = true;
1284 mHandler.removeCallbacks(mWriteRunner);
1285 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001286 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001287 }
1288
Dianne Hackborn72e39832013-01-18 18:36:09 -08001289 private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001290 Ops ops = getOpsRawLocked(uid, packageName, edit);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001291 if (ops == null) {
1292 return null;
1293 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001294 return getOpLocked(ops, code, edit);
1295 }
1296
1297 private Op getOpLocked(Ops ops, int code, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001298 Op op = ops.get(code);
1299 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001300 if (!edit) {
1301 return null;
1302 }
Svet Ganov2af57082015-07-30 08:44:20 -07001303 op = new Op(ops.uidState.uid, ops.packageName, code);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001304 ops.put(code, op);
1305 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001306 if (edit) {
1307 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001308 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001309 return op;
1310 }
1311
Svet Ganov442ed572016-08-17 17:29:43 -07001312 private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
Jason Monk62062992014-05-06 09:55:28 -04001313 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001314 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08001315
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001316 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08001317 // For each client, check that the given op is not restricted, or that the given
1318 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07001319 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07001320 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
1321 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
1322 // If we are the system, bypass user restrictions for certain codes
1323 synchronized (this) {
1324 Ops ops = getOpsRawLocked(uid, packageName, true);
1325 if ((ops != null) && ops.isPrivileged) {
1326 return false;
1327 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08001328 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08001329 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08001330 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04001331 }
Jason Monk62062992014-05-06 09:55:28 -04001332 }
1333 return false;
1334 }
1335
Dianne Hackborn35654b62013-01-14 17:38:02 -08001336 void readState() {
1337 synchronized (mFile) {
1338 synchronized (this) {
1339 FileInputStream stream;
1340 try {
1341 stream = mFile.openRead();
1342 } catch (FileNotFoundException e) {
1343 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
1344 return;
1345 }
1346 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001347 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001348 try {
1349 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001350 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08001351 int type;
1352 while ((type = parser.next()) != XmlPullParser.START_TAG
1353 && type != XmlPullParser.END_DOCUMENT) {
1354 ;
1355 }
1356
1357 if (type != XmlPullParser.START_TAG) {
1358 throw new IllegalStateException("no start tag found");
1359 }
1360
1361 int outerDepth = parser.getDepth();
1362 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1363 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1364 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1365 continue;
1366 }
1367
1368 String tagName = parser.getName();
1369 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001370 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07001371 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07001372 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001373 } else {
1374 Slog.w(TAG, "Unknown element under <app-ops>: "
1375 + parser.getName());
1376 XmlUtils.skipCurrentTag(parser);
1377 }
1378 }
1379 success = true;
1380 } catch (IllegalStateException e) {
1381 Slog.w(TAG, "Failed parsing " + e);
1382 } catch (NullPointerException e) {
1383 Slog.w(TAG, "Failed parsing " + e);
1384 } catch (NumberFormatException e) {
1385 Slog.w(TAG, "Failed parsing " + e);
1386 } catch (XmlPullParserException e) {
1387 Slog.w(TAG, "Failed parsing " + e);
1388 } catch (IOException e) {
1389 Slog.w(TAG, "Failed parsing " + e);
1390 } catch (IndexOutOfBoundsException e) {
1391 Slog.w(TAG, "Failed parsing " + e);
1392 } finally {
1393 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07001394 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001395 }
1396 try {
1397 stream.close();
1398 } catch (IOException e) {
1399 }
1400 }
1401 }
1402 }
1403 }
1404
Svet Ganov2af57082015-07-30 08:44:20 -07001405 void readUidOps(XmlPullParser parser) throws NumberFormatException,
1406 XmlPullParserException, IOException {
1407 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
1408 int outerDepth = parser.getDepth();
1409 int type;
1410 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1411 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1412 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1413 continue;
1414 }
1415
1416 String tagName = parser.getName();
1417 if (tagName.equals("op")) {
1418 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
1419 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
1420 UidState uidState = getUidStateLocked(uid, true);
1421 if (uidState.opModes == null) {
1422 uidState.opModes = new SparseIntArray();
1423 }
1424 uidState.opModes.put(code, mode);
1425 } else {
1426 Slog.w(TAG, "Unknown element under <uid-ops>: "
1427 + parser.getName());
1428 XmlUtils.skipCurrentTag(parser);
1429 }
1430 }
1431 }
1432
Dave Burke0997c5bd2013-08-02 20:25:02 +00001433 void readPackage(XmlPullParser parser) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08001434 XmlPullParserException, IOException {
1435 String pkgName = parser.getAttributeValue(null, "n");
1436 int outerDepth = parser.getDepth();
1437 int type;
1438 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1439 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1440 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1441 continue;
1442 }
1443
1444 String tagName = parser.getName();
1445 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001446 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001447 } else {
1448 Slog.w(TAG, "Unknown element under <pkg>: "
1449 + parser.getName());
1450 XmlUtils.skipCurrentTag(parser);
1451 }
1452 }
1453 }
1454
Dave Burke0997c5bd2013-08-02 20:25:02 +00001455 void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
Dianne Hackborn35654b62013-01-14 17:38:02 -08001456 XmlPullParserException, IOException {
1457 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Jason Monk1c7c3192014-06-26 12:52:18 -04001458 String isPrivilegedString = parser.getAttributeValue(null, "p");
1459 boolean isPrivileged = false;
1460 if (isPrivilegedString == null) {
1461 try {
1462 IPackageManager packageManager = ActivityThread.getPackageManager();
1463 if (packageManager != null) {
1464 ApplicationInfo appInfo = ActivityThread.getPackageManager()
1465 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
1466 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001467 isPrivileged = (appInfo.privateFlags
1468 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04001469 }
1470 } else {
1471 // Could not load data, don't add to cache so it will be loaded later.
1472 return;
1473 }
1474 } catch (RemoteException e) {
1475 Slog.w(TAG, "Could not contact PackageManager", e);
1476 }
1477 } else {
1478 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
1479 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001480 int outerDepth = parser.getDepth();
1481 int type;
1482 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1483 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1484 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1485 continue;
1486 }
1487
1488 String tagName = parser.getName();
1489 if (tagName.equals("op")) {
Dianne Hackborne98f5db2013-07-17 17:23:25 -07001490 Op op = new Op(uid, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n")));
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001491 String mode = parser.getAttributeValue(null, "m");
1492 if (mode != null) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00001493 op.mode = Integer.parseInt(mode);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001494 }
1495 String time = parser.getAttributeValue(null, "t");
1496 if (time != null) {
1497 op.time = Long.parseLong(time);
1498 }
1499 time = parser.getAttributeValue(null, "r");
1500 if (time != null) {
1501 op.rejectTime = Long.parseLong(time);
1502 }
1503 String dur = parser.getAttributeValue(null, "d");
1504 if (dur != null) {
1505 op.duration = Integer.parseInt(dur);
1506 }
Svet Ganov99b60432015-06-27 13:15:22 -07001507 String proxyUid = parser.getAttributeValue(null, "pu");
1508 if (proxyUid != null) {
1509 op.proxyUid = Integer.parseInt(proxyUid);
1510 }
1511 String proxyPackageName = parser.getAttributeValue(null, "pp");
1512 if (proxyPackageName != null) {
1513 op.proxyPackageName = proxyPackageName;
1514 }
Svet Ganov2af57082015-07-30 08:44:20 -07001515
1516 UidState uidState = getUidStateLocked(uid, true);
1517 if (uidState.pkgOps == null) {
1518 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborn35654b62013-01-14 17:38:02 -08001519 }
Svet Ganov2af57082015-07-30 08:44:20 -07001520
1521 Ops ops = uidState.pkgOps.get(pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001522 if (ops == null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001523 ops = new Ops(pkgName, uidState, isPrivileged);
1524 uidState.pkgOps.put(pkgName, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001525 }
1526 ops.put(op.op, op);
1527 } else {
1528 Slog.w(TAG, "Unknown element under <pkg>: "
1529 + parser.getName());
1530 XmlUtils.skipCurrentTag(parser);
1531 }
1532 }
1533 }
1534
1535 void writeState() {
1536 synchronized (mFile) {
1537 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
1538
1539 FileOutputStream stream;
1540 try {
1541 stream = mFile.startWrite();
1542 } catch (IOException e) {
1543 Slog.w(TAG, "Failed to write state: " + e);
1544 return;
1545 }
1546
1547 try {
1548 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001549 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08001550 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001551 out.startTag(null, "app-ops");
Svet Ganov2af57082015-07-30 08:44:20 -07001552
1553 final int uidStateCount = mUidStates.size();
1554 for (int i = 0; i < uidStateCount; i++) {
1555 UidState uidState = mUidStates.valueAt(i);
1556 if (uidState.opModes != null && uidState.opModes.size() > 0) {
1557 out.startTag(null, "uid");
1558 out.attribute(null, "n", Integer.toString(uidState.uid));
1559 SparseIntArray uidOpModes = uidState.opModes;
1560 final int opCount = uidOpModes.size();
1561 for (int j = 0; j < opCount; j++) {
1562 final int op = uidOpModes.keyAt(j);
1563 final int mode = uidOpModes.valueAt(j);
1564 out.startTag(null, "op");
1565 out.attribute(null, "n", Integer.toString(op));
1566 out.attribute(null, "m", Integer.toString(mode));
1567 out.endTag(null, "op");
1568 }
1569 out.endTag(null, "uid");
1570 }
1571 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001572
1573 if (allOps != null) {
1574 String lastPkg = null;
1575 for (int i=0; i<allOps.size(); i++) {
1576 AppOpsManager.PackageOps pkg = allOps.get(i);
1577 if (!pkg.getPackageName().equals(lastPkg)) {
1578 if (lastPkg != null) {
1579 out.endTag(null, "pkg");
1580 }
1581 lastPkg = pkg.getPackageName();
1582 out.startTag(null, "pkg");
1583 out.attribute(null, "n", lastPkg);
1584 }
1585 out.startTag(null, "uid");
1586 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04001587 synchronized (this) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001588 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
Jason Monk1c7c3192014-06-26 12:52:18 -04001589 // Should always be present as the list of PackageOps is generated
1590 // from Ops.
1591 if (ops != null) {
1592 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
1593 } else {
1594 out.attribute(null, "p", Boolean.toString(false));
1595 }
1596 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001597 List<AppOpsManager.OpEntry> ops = pkg.getOps();
1598 for (int j=0; j<ops.size(); j++) {
1599 AppOpsManager.OpEntry op = ops.get(j);
1600 out.startTag(null, "op");
1601 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07001602 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001603 out.attribute(null, "m", Integer.toString(op.getMode()));
1604 }
1605 long time = op.getTime();
1606 if (time != 0) {
1607 out.attribute(null, "t", Long.toString(time));
1608 }
1609 time = op.getRejectTime();
1610 if (time != 0) {
1611 out.attribute(null, "r", Long.toString(time));
1612 }
1613 int dur = op.getDuration();
1614 if (dur != 0) {
1615 out.attribute(null, "d", Integer.toString(dur));
1616 }
Svet Ganov99b60432015-06-27 13:15:22 -07001617 int proxyUid = op.getProxyUid();
1618 if (proxyUid != -1) {
1619 out.attribute(null, "pu", Integer.toString(proxyUid));
1620 }
1621 String proxyPackageName = op.getProxyPackageName();
1622 if (proxyPackageName != null) {
1623 out.attribute(null, "pp", proxyPackageName);
1624 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001625 out.endTag(null, "op");
1626 }
1627 out.endTag(null, "uid");
1628 }
1629 if (lastPkg != null) {
1630 out.endTag(null, "pkg");
1631 }
1632 }
1633
1634 out.endTag(null, "app-ops");
1635 out.endDocument();
1636 mFile.finishWrite(stream);
1637 } catch (IOException e) {
1638 Slog.w(TAG, "Failed to write state, restoring backup.", e);
1639 mFile.failWrite(stream);
1640 }
1641 }
1642 }
1643
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001644 static class Shell extends ShellCommand {
1645 final IAppOpsService mInterface;
1646 final AppOpsService mInternal;
1647
1648 int userId = UserHandle.USER_SYSTEM;
1649 String packageName;
1650 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001651 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001652 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001653 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001654 int packageUid;
1655
1656 Shell(IAppOpsService iface, AppOpsService internal) {
1657 mInterface = iface;
1658 mInternal = internal;
1659 }
1660
1661 @Override
1662 public int onCommand(String cmd) {
1663 return onShellCommand(this, cmd);
1664 }
1665
1666 @Override
1667 public void onHelp() {
1668 PrintWriter pw = getOutPrintWriter();
1669 dumpCommandHelp(pw);
1670 }
1671
1672 private int strOpToOp(String op, PrintWriter err) {
1673 try {
1674 return AppOpsManager.strOpToOp(op);
1675 } catch (IllegalArgumentException e) {
1676 }
1677 try {
1678 return Integer.parseInt(op);
1679 } catch (NumberFormatException e) {
1680 }
1681 try {
1682 return AppOpsManager.strDebugOpToOp(op);
1683 } catch (IllegalArgumentException e) {
1684 err.println("Error: " + e.getMessage());
1685 return -1;
1686 }
1687 }
1688
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001689 int strModeToMode(String modeStr, PrintWriter err) {
1690 switch (modeStr) {
1691 case "allow":
1692 return AppOpsManager.MODE_ALLOWED;
1693 case "deny":
1694 return AppOpsManager.MODE_ERRORED;
1695 case "ignore":
1696 return AppOpsManager.MODE_IGNORED;
1697 case "default":
1698 return AppOpsManager.MODE_DEFAULT;
1699 }
1700 try {
1701 return Integer.parseInt(modeStr);
1702 } catch (NumberFormatException e) {
1703 }
1704 err.println("Error: Mode " + modeStr + " is not valid");
1705 return -1;
1706 }
1707
1708 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
1709 userId = UserHandle.USER_CURRENT;
1710 opStr = null;
1711 modeStr = null;
1712 for (String argument; (argument = getNextArg()) != null;) {
1713 if ("--user".equals(argument)) {
1714 userId = UserHandle.parseUserArg(getNextArgRequired());
1715 } else {
1716 if (opStr == null) {
1717 opStr = argument;
1718 } else if (modeStr == null) {
1719 modeStr = argument;
1720 break;
1721 }
1722 }
1723 }
1724 if (opStr == null) {
1725 err.println("Error: Operation not specified.");
1726 return -1;
1727 }
1728 op = strOpToOp(opStr, err);
1729 if (op < 0) {
1730 return -1;
1731 }
1732 if (modeStr != null) {
1733 if ((mode=strModeToMode(modeStr, err)) < 0) {
1734 return -1;
1735 }
1736 } else {
1737 mode = defMode;
1738 }
1739 return 0;
1740 }
1741
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001742 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
1743 userId = UserHandle.USER_CURRENT;
1744 packageName = null;
1745 opStr = null;
1746 for (String argument; (argument = getNextArg()) != null;) {
1747 if ("--user".equals(argument)) {
1748 userId = UserHandle.parseUserArg(getNextArgRequired());
1749 } else {
1750 if (packageName == null) {
1751 packageName = argument;
1752 } else if (opStr == null) {
1753 opStr = argument;
1754 break;
1755 }
1756 }
1757 }
1758 if (packageName == null) {
1759 err.println("Error: Package name not specified.");
1760 return -1;
1761 } else if (opStr == null && reqOp) {
1762 err.println("Error: Operation not specified.");
1763 return -1;
1764 }
1765 if (opStr != null) {
1766 op = strOpToOp(opStr, err);
1767 if (op < 0) {
1768 return -1;
1769 }
1770 } else {
1771 op = AppOpsManager.OP_NONE;
1772 }
1773 if (userId == UserHandle.USER_CURRENT) {
1774 userId = ActivityManager.getCurrentUser();
1775 }
1776 if ("root".equals(packageName)) {
1777 packageUid = 0;
1778 } else {
Jeff Sharkeycd654482016-01-08 17:42:11 -07001779 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
1780 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001781 }
1782 if (packageUid < 0) {
1783 err.println("Error: No UID for " + packageName + " in user " + userId);
1784 return -1;
1785 }
1786 return 0;
1787 }
1788 }
1789
1790 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001791 FileDescriptor err, String[] args, ShellCallback callback,
1792 ResultReceiver resultReceiver) {
1793 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001794 }
1795
1796 static void dumpCommandHelp(PrintWriter pw) {
1797 pw.println("AppOps service (appops) commands:");
1798 pw.println(" help");
1799 pw.println(" Print this help text.");
1800 pw.println(" set [--user <USER_ID>] <PACKAGE> <OP> <MODE>");
1801 pw.println(" Set the mode for a particular application and operation.");
1802 pw.println(" get [--user <USER_ID>] <PACKAGE> [<OP>]");
1803 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001804 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
1805 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001806 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
1807 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07001808 pw.println(" write-settings");
1809 pw.println(" Immediately write pending changes to storage.");
1810 pw.println(" read-settings");
1811 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001812 pw.println(" options:");
1813 pw.println(" <PACKAGE> an Android package name.");
1814 pw.println(" <OP> an AppOps operation.");
1815 pw.println(" <MODE> one of allow, ignore, deny, or default");
1816 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
1817 pw.println(" specified, the current user is assumed.");
1818 }
1819
1820 static int onShellCommand(Shell shell, String cmd) {
1821 if (cmd == null) {
1822 return shell.handleDefaultCommands(cmd);
1823 }
1824 PrintWriter pw = shell.getOutPrintWriter();
1825 PrintWriter err = shell.getErrPrintWriter();
1826 try {
1827 switch (cmd) {
1828 case "set": {
1829 int res = shell.parseUserPackageOp(true, err);
1830 if (res < 0) {
1831 return res;
1832 }
1833 String modeStr = shell.getNextArg();
1834 if (modeStr == null) {
1835 err.println("Error: Mode not specified.");
1836 return -1;
1837 }
1838
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001839 final int mode = shell.strModeToMode(modeStr, err);
1840 if (mode < 0) {
1841 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001842 }
1843
1844 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode);
1845 return 0;
1846 }
1847 case "get": {
1848 int res = shell.parseUserPackageOp(false, err);
1849 if (res < 0) {
1850 return res;
1851 }
1852
1853 List<AppOpsManager.PackageOps> ops = shell.mInterface.getOpsForPackage(
1854 shell.packageUid, shell.packageName,
1855 shell.op != AppOpsManager.OP_NONE ? new int[] {shell.op} : null);
1856 if (ops == null || ops.size() <= 0) {
1857 pw.println("No operations.");
1858 return 0;
1859 }
1860 final long now = System.currentTimeMillis();
1861 for (int i=0; i<ops.size(); i++) {
1862 List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
1863 for (int j=0; j<entries.size(); j++) {
1864 AppOpsManager.OpEntry ent = entries.get(j);
1865 pw.print(AppOpsManager.opToName(ent.getOp()));
1866 pw.print(": ");
1867 switch (ent.getMode()) {
1868 case AppOpsManager.MODE_ALLOWED:
1869 pw.print("allow");
1870 break;
1871 case AppOpsManager.MODE_IGNORED:
1872 pw.print("ignore");
1873 break;
1874 case AppOpsManager.MODE_ERRORED:
1875 pw.print("deny");
1876 break;
1877 case AppOpsManager.MODE_DEFAULT:
1878 pw.print("default");
1879 break;
1880 default:
1881 pw.print("mode=");
1882 pw.print(ent.getMode());
1883 break;
1884 }
1885 if (ent.getTime() != 0) {
1886 pw.print("; time=");
1887 TimeUtils.formatDuration(now - ent.getTime(), pw);
1888 pw.print(" ago");
1889 }
1890 if (ent.getRejectTime() != 0) {
1891 pw.print("; rejectTime=");
1892 TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
1893 pw.print(" ago");
1894 }
1895 if (ent.getDuration() == -1) {
1896 pw.print(" (running)");
1897 } else if (ent.getDuration() != 0) {
1898 pw.print("; duration=");
1899 TimeUtils.formatDuration(ent.getDuration(), pw);
1900 }
1901 pw.println();
1902 }
1903 }
1904 return 0;
1905 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07001906 case "query-op": {
1907 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
1908 if (res < 0) {
1909 return res;
1910 }
1911 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
1912 new int[] {shell.op});
1913 if (ops == null || ops.size() <= 0) {
1914 pw.println("No operations.");
1915 return 0;
1916 }
1917 for (int i=0; i<ops.size(); i++) {
1918 final AppOpsManager.PackageOps pkg = ops.get(i);
1919 boolean hasMatch = false;
1920 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
1921 for (int j=0; j<entries.size(); j++) {
1922 AppOpsManager.OpEntry ent = entries.get(j);
1923 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
1924 hasMatch = true;
1925 break;
1926 }
1927 }
1928 if (hasMatch) {
1929 pw.println(pkg.getPackageName());
1930 }
1931 }
1932 return 0;
1933 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08001934 case "reset": {
1935 String packageName = null;
1936 int userId = UserHandle.USER_CURRENT;
1937 for (String argument; (argument = shell.getNextArg()) != null;) {
1938 if ("--user".equals(argument)) {
1939 String userStr = shell.getNextArgRequired();
1940 userId = UserHandle.parseUserArg(userStr);
1941 } else {
1942 if (packageName == null) {
1943 packageName = argument;
1944 } else {
1945 err.println("Error: Unsupported argument: " + argument);
1946 return -1;
1947 }
1948 }
1949 }
1950
1951 if (userId == UserHandle.USER_CURRENT) {
1952 userId = ActivityManager.getCurrentUser();
1953 }
1954
1955 shell.mInterface.resetAllModes(userId, packageName);
1956 pw.print("Reset all modes for: ");
1957 if (userId == UserHandle.USER_ALL) {
1958 pw.print("all users");
1959 } else {
1960 pw.print("user "); pw.print(userId);
1961 }
1962 pw.print(", ");
1963 if (packageName == null) {
1964 pw.println("all packages");
1965 } else {
1966 pw.print("package "); pw.println(packageName);
1967 }
1968 return 0;
1969 }
1970 case "write-settings": {
1971 shell.mInternal.mContext.enforcePermission(
1972 android.Manifest.permission.UPDATE_APP_OPS_STATS,
1973 Binder.getCallingPid(), Binder.getCallingUid(), null);
1974 long token = Binder.clearCallingIdentity();
1975 try {
1976 synchronized (shell.mInternal) {
1977 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
1978 }
1979 shell.mInternal.writeState();
1980 pw.println("Current settings written.");
1981 } finally {
1982 Binder.restoreCallingIdentity(token);
1983 }
1984 return 0;
1985 }
1986 case "read-settings": {
1987 shell.mInternal.mContext.enforcePermission(
1988 android.Manifest.permission.UPDATE_APP_OPS_STATS,
1989 Binder.getCallingPid(), Binder.getCallingUid(), null);
1990 long token = Binder.clearCallingIdentity();
1991 try {
1992 shell.mInternal.readState();
1993 pw.println("Last settings read.");
1994 } finally {
1995 Binder.restoreCallingIdentity(token);
1996 }
1997 return 0;
1998 }
1999 default:
2000 return shell.handleDefaultCommands(cmd);
2001 }
2002 } catch (RemoteException e) {
2003 pw.println("Remote exception: " + e);
2004 }
2005 return -1;
2006 }
2007
2008 private void dumpHelp(PrintWriter pw) {
2009 pw.println("AppOps service (appops) dump options:");
2010 pw.println(" none");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002011 }
2012
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002013 @Override
2014 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2015 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2016 != PackageManager.PERMISSION_GRANTED) {
2017 pw.println("Permission Denial: can't dump ApOps service from from pid="
2018 + Binder.getCallingPid()
2019 + ", uid=" + Binder.getCallingUid());
2020 return;
2021 }
2022
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002023 if (args != null) {
2024 for (int i=0; i<args.length; i++) {
2025 String arg = args[i];
2026 if ("-h".equals(arg)) {
2027 dumpHelp(pw);
2028 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07002029 } else if ("-a".equals(arg)) {
2030 // dump all data
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07002031 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
2032 pw.println("Unknown option: " + arg);
2033 return;
2034 } else {
2035 pw.println("Unknown command: " + arg);
2036 return;
2037 }
2038 }
2039 }
2040
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002041 synchronized (this) {
2042 pw.println("Current AppOps Service state:");
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002043 final long now = System.currentTimeMillis();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002044 boolean needSep = false;
2045 if (mOpModeWatchers.size() > 0) {
2046 needSep = true;
2047 pw.println(" Op mode watchers:");
2048 for (int i=0; i<mOpModeWatchers.size(); i++) {
2049 pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
2050 pw.println(":");
2051 ArrayList<Callback> callbacks = mOpModeWatchers.valueAt(i);
2052 for (int j=0; j<callbacks.size(); j++) {
2053 pw.print(" #"); pw.print(j); pw.print(": ");
2054 pw.println(callbacks.get(j));
2055 }
2056 }
2057 }
2058 if (mPackageModeWatchers.size() > 0) {
2059 needSep = true;
2060 pw.println(" Package mode watchers:");
2061 for (int i=0; i<mPackageModeWatchers.size(); i++) {
2062 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
2063 pw.println(":");
2064 ArrayList<Callback> callbacks = mPackageModeWatchers.valueAt(i);
2065 for (int j=0; j<callbacks.size(); j++) {
2066 pw.print(" #"); pw.print(j); pw.print(": ");
2067 pw.println(callbacks.get(j));
2068 }
2069 }
2070 }
2071 if (mModeWatchers.size() > 0) {
2072 needSep = true;
2073 pw.println(" All mode watchers:");
2074 for (int i=0; i<mModeWatchers.size(); i++) {
2075 pw.print(" "); pw.print(mModeWatchers.keyAt(i));
2076 pw.print(" -> "); pw.println(mModeWatchers.valueAt(i));
2077 }
2078 }
2079 if (mClients.size() > 0) {
2080 needSep = true;
2081 pw.println(" Clients:");
2082 for (int i=0; i<mClients.size(); i++) {
2083 pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":");
2084 ClientState cs = mClients.valueAt(i);
2085 pw.print(" "); pw.println(cs);
2086 if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) {
2087 pw.println(" Started ops:");
2088 for (int j=0; j<cs.mStartedOps.size(); j++) {
2089 Op op = cs.mStartedOps.get(j);
2090 pw.print(" "); pw.print("uid="); pw.print(op.uid);
2091 pw.print(" pkg="); pw.print(op.packageName);
2092 pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
2093 }
2094 }
2095 }
2096 }
John Spurlock1af30c72014-03-10 08:33:35 -04002097 if (mAudioRestrictions.size() > 0) {
2098 boolean printedHeader = false;
2099 for (int o=0; o<mAudioRestrictions.size(); o++) {
2100 final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
2101 final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
2102 for (int i=0; i<restrictions.size(); i++) {
2103 if (!printedHeader){
2104 pw.println(" Audio Restrictions:");
2105 printedHeader = true;
2106 needSep = true;
2107 }
John Spurlock7b414672014-07-18 13:02:39 -04002108 final int usage = restrictions.keyAt(i);
John Spurlock1af30c72014-03-10 08:33:35 -04002109 pw.print(" "); pw.print(op);
John Spurlock7b414672014-07-18 13:02:39 -04002110 pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
John Spurlock1af30c72014-03-10 08:33:35 -04002111 Restriction r = restrictions.valueAt(i);
2112 pw.print(": mode="); pw.println(r.mode);
2113 if (!r.exceptionPackages.isEmpty()) {
2114 pw.println(" Exceptions:");
2115 for (int j=0; j<r.exceptionPackages.size(); j++) {
2116 pw.print(" "); pw.println(r.exceptionPackages.valueAt(j));
2117 }
2118 }
2119 }
2120 }
2121 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002122 if (needSep) {
2123 pw.println();
2124 }
Svet Ganov2af57082015-07-30 08:44:20 -07002125 for (int i=0; i<mUidStates.size(); i++) {
2126 UidState uidState = mUidStates.valueAt(i);
2127
2128 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
2129
2130 SparseIntArray opModes = uidState.opModes;
2131 if (opModes != null) {
2132 final int opModeCount = opModes.size();
2133 for (int j = 0; j < opModeCount; j++) {
2134 final int code = opModes.keyAt(j);
2135 final int mode = opModes.valueAt(j);
2136 pw.print(" "); pw.print(AppOpsManager.opToName(code));
2137 pw.print(": mode="); pw.println(mode);
2138 }
2139 }
2140
2141 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
2142 if (pkgOps == null) {
2143 continue;
2144 }
2145
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002146 for (Ops ops : pkgOps.values()) {
2147 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
2148 for (int j=0; j<ops.size(); j++) {
2149 Op op = ops.valueAt(j);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002150 pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
2151 pw.print(": mode="); pw.print(op.mode);
2152 if (op.time != 0) {
2153 pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
2154 pw.print(" ago");
2155 }
2156 if (op.rejectTime != 0) {
2157 pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
2158 pw.print(" ago");
2159 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002160 if (op.duration == -1) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002161 pw.print(" (running)");
2162 } else if (op.duration != 0) {
2163 pw.print("; duration="); TimeUtils.formatDuration(op.duration, pw);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002164 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002165 pw.println();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002166 }
2167 }
2168 }
2169 }
2170 }
John Spurlock1af30c72014-03-10 08:33:35 -04002171
2172 private static final class Restriction {
2173 private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
2174 int mode;
2175 ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
2176 }
Jason Monk62062992014-05-06 09:55:28 -04002177
2178 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002179 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04002180 checkSystemUid("setUserRestrictions");
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002181 Preconditions.checkNotNull(restrictions);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002182 Preconditions.checkNotNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002183 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04002184 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07002185 if (restriction != null) {
2186 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
2187 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002188 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002189 }
2190 }
2191
2192 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08002193 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
2194 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002195 if (Binder.getCallingPid() != Process.myPid()) {
2196 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
2197 Binder.getCallingPid(), Binder.getCallingUid(), null);
2198 }
2199 if (userHandle != UserHandle.getCallingUserId()) {
2200 if (mContext.checkCallingOrSelfPermission(Manifest.permission
2201 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
2202 && mContext.checkCallingOrSelfPermission(Manifest.permission
2203 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
2204 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
2205 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04002206 }
2207 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002208 verifyIncomingOp(code);
2209 Preconditions.checkNotNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002210 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002211 }
2212
2213 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08002214 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07002215 boolean notifyChange = false;
Ruben Brunk29931bc2016-03-11 00:24:26 -08002216
Svet Ganov442ed572016-08-17 17:29:43 -07002217 synchronized (AppOpsService.this) {
2218 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
2219
2220 if (restrictionState == null) {
2221 try {
2222 restrictionState = new ClientRestrictionState(token);
2223 } catch (RemoteException e) {
2224 return;
2225 }
2226 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08002227 }
Svet Ganov442ed572016-08-17 17:29:43 -07002228
2229 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
2230 notifyChange = true;
2231 }
2232
2233 if (restrictionState.isDefault()) {
2234 mOpUserRestrictions.remove(token);
2235 restrictionState.destroy();
2236 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08002237 }
2238
Svet Ganov442ed572016-08-17 17:29:43 -07002239 if (notifyChange) {
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002240 notifyWatchersOfChange(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002241 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04002242 }
2243
2244 private void notifyWatchersOfChange(int code) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002245 final ArrayList<Callback> clonedCallbacks;
2246 synchronized (this) {
2247 ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
2248 if (callbacks == null) {
2249 return;
2250 }
2251 clonedCallbacks = new ArrayList<>(callbacks);
2252 }
2253
2254 // There are components watching for mode changes such as window manager
2255 // and location manager which are in our process. The callbacks in these
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002256 // components may require permissions our remote caller does not have.s
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002257 final long identity = Binder.clearCallingIdentity();
2258 try {
2259 final int callbackCount = clonedCallbacks.size();
2260 for (int i = 0; i < callbackCount; i++) {
2261 Callback callback = clonedCallbacks.get(i);
2262 try {
2263 callback.mCallback.opChanged(code, -1, null);
2264 } catch (RemoteException e) {
2265 Log.w(TAG, "Error dispatching op op change", e);
2266 }
2267 }
2268 } finally {
2269 Binder.restoreCallingIdentity(identity);
2270 }
Jason Monk62062992014-05-06 09:55:28 -04002271 }
2272
2273 @Override
2274 public void removeUser(int userHandle) throws RemoteException {
2275 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07002276 synchronized (AppOpsService.this) {
2277 final int tokenCount = mOpUserRestrictions.size();
2278 for (int i = tokenCount - 1; i >= 0; i--) {
2279 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
2280 opRestrictions.removeUser(userHandle);
2281 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07002282 removeUidsForUserLocked(userHandle);
2283 }
2284 }
2285
2286 private void removeUidsForUserLocked(int userHandle) {
2287 for (int i = mUidStates.size() - 1; i >= 0; --i) {
2288 final int uid = mUidStates.keyAt(i);
2289 if (UserHandle.getUserId(uid) == userHandle) {
2290 mUidStates.removeAt(i);
2291 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08002292 }
2293 }
2294
Jason Monk62062992014-05-06 09:55:28 -04002295 private void checkSystemUid(String function) {
2296 int uid = Binder.getCallingUid();
2297 if (uid != Process.SYSTEM_UID) {
2298 throw new SecurityException(function + " must by called by the system");
2299 }
2300 }
2301
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002302 private static String resolvePackageName(int uid, String packageName) {
2303 if (uid == 0) {
2304 return "root";
2305 } else if (uid == Process.SHELL_UID) {
2306 return "com.android.shell";
2307 } else if (uid == Process.SYSTEM_UID && packageName == null) {
2308 return "android";
2309 }
2310 return packageName;
2311 }
2312
Svet Ganov2af57082015-07-30 08:44:20 -07002313 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07002314 String[] packageNames = null;
Svet Ganov2af57082015-07-30 08:44:20 -07002315 try {
riddle_hsu40b300f2015-11-23 13:22:03 +08002316 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
Svet Ganov2af57082015-07-30 08:44:20 -07002317 } catch (RemoteException e) {
2318 /* ignore - local call */
2319 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07002320 if (packageNames == null) {
2321 return EmptyArray.STRING;
2322 }
2323 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07002324 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002325
2326 private final class ClientRestrictionState implements DeathRecipient {
2327 private final IBinder token;
2328 SparseArray<boolean[]> perUserRestrictions;
2329 SparseArray<String[]> perUserExcludedPackages;
2330
2331 public ClientRestrictionState(IBinder token)
2332 throws RemoteException {
2333 token.linkToDeath(this, 0);
2334 this.token = token;
2335 }
2336
2337 public boolean setRestriction(int code, boolean restricted,
2338 String[] excludedPackages, int userId) {
2339 boolean changed = false;
2340
2341 if (perUserRestrictions == null && restricted) {
2342 perUserRestrictions = new SparseArray<>();
2343 }
2344
2345 if (perUserRestrictions != null) {
2346 boolean[] userRestrictions = perUserRestrictions.get(userId);
2347 if (userRestrictions == null && restricted) {
2348 userRestrictions = new boolean[AppOpsManager._NUM_OP];
2349 perUserRestrictions.put(userId, userRestrictions);
2350 }
2351 if (userRestrictions != null && userRestrictions[code] != restricted) {
2352 userRestrictions[code] = restricted;
2353 if (!restricted && isDefault(userRestrictions)) {
2354 perUserRestrictions.remove(userId);
2355 userRestrictions = null;
2356 }
2357 changed = true;
2358 }
2359
2360 if (userRestrictions != null) {
2361 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
2362 if (perUserExcludedPackages == null && !noExcludedPackages) {
2363 perUserExcludedPackages = new SparseArray<>();
2364 }
2365 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
2366 perUserExcludedPackages.get(userId))) {
2367 if (noExcludedPackages) {
2368 perUserExcludedPackages.remove(userId);
2369 if (perUserExcludedPackages.size() <= 0) {
2370 perUserExcludedPackages = null;
2371 }
2372 } else {
2373 perUserExcludedPackages.put(userId, excludedPackages);
2374 }
2375 changed = true;
2376 }
2377 }
2378 }
2379
2380 return changed;
2381 }
2382
2383 public boolean hasRestriction(int restriction, String packageName, int userId) {
2384 if (perUserRestrictions == null) {
2385 return false;
2386 }
2387 boolean[] restrictions = perUserRestrictions.get(userId);
2388 if (restrictions == null) {
2389 return false;
2390 }
2391 if (!restrictions[restriction]) {
2392 return false;
2393 }
2394 if (perUserExcludedPackages == null) {
2395 return true;
2396 }
2397 String[] perUserExclusions = perUserExcludedPackages.get(userId);
2398 if (perUserExclusions == null) {
2399 return true;
2400 }
2401 return !ArrayUtils.contains(perUserExclusions, packageName);
2402 }
2403
2404 public void removeUser(int userId) {
2405 if (perUserExcludedPackages != null) {
2406 perUserExcludedPackages.remove(userId);
2407 if (perUserExcludedPackages.size() <= 0) {
2408 perUserExcludedPackages = null;
2409 }
2410 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07002411 if (perUserRestrictions != null) {
2412 perUserRestrictions.remove(userId);
2413 if (perUserRestrictions.size() <= 0) {
2414 perUserRestrictions = null;
2415 }
2416 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07002417 }
2418
2419 public boolean isDefault() {
2420 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
2421 }
2422
2423 @Override
2424 public void binderDied() {
2425 synchronized (AppOpsService.this) {
2426 mOpUserRestrictions.remove(token);
2427 if (perUserRestrictions == null) {
2428 return;
2429 }
2430 final int userCount = perUserRestrictions.size();
2431 for (int i = 0; i < userCount; i++) {
2432 final boolean[] restrictions = perUserRestrictions.valueAt(i);
2433 final int restrictionCount = restrictions.length;
2434 for (int j = 0; j < restrictionCount; j++) {
2435 if (restrictions[j]) {
2436 final int changedCode = j;
2437 mHandler.post(() -> notifyWatchersOfChange(changedCode));
2438 }
2439 }
2440 }
2441 destroy();
2442 }
2443 }
2444
2445 public void destroy() {
2446 token.unlinkToDeath(this, 0);
2447 }
2448
2449 private boolean isDefault(boolean[] array) {
2450 if (ArrayUtils.isEmpty(array)) {
2451 return true;
2452 }
2453 for (boolean value : array) {
2454 if (value) {
2455 return false;
2456 }
2457 }
2458 return true;
2459 }
2460 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002461}