blob: 1d714a2c99c7dbbe169b1b02eba3e60b42786147 [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
Svet Ganov8455ba22019-01-02 13:05:56 -080017package com.android.server.appop;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080018
Hui Yu85679b42020-01-15 15:52:08 -080019import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
Hui Yu26969322019-08-21 14:56:35 -070020import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
Hui Yu85679b42020-01-15 15:52:08 -080021import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
Philip P. Moltmann4aacd712020-01-03 12:32:20 -080022import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID;
23import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
24import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
25import static android.app.AppOpsManager.FILTER_BY_UID;
26import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
Hui Yu88910de2019-12-16 14:35:27 -080027import static android.app.AppOpsManager.MODE_ALLOWED;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -080028import static android.app.AppOpsManager.NoteOpEvent;
Suprabh Shukla7e017922019-08-05 17:13:23 -070029import static android.app.AppOpsManager.OP_CAMERA;
Hai Zhang2a31fd72019-12-10 15:48:22 -080030import static android.app.AppOpsManager.OP_COARSE_LOCATION;
Svet Ganovaf189e32019-02-15 18:45:29 -080031import static android.app.AppOpsManager.OP_FLAGS_ALL;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -080032import static android.app.AppOpsManager.OP_FLAG_SELF;
Svet Ganov8455ba22019-01-02 13:05:56 -080033import static android.app.AppOpsManager.OP_NONE;
Philip P. Moltmanndde07852019-01-25 16:42:36 -080034import static android.app.AppOpsManager.OP_PLAY_AUDIO;
Suprabh Shukla7e017922019-08-05 17:13:23 -070035import static android.app.AppOpsManager.OP_RECORD_AUDIO;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080036import static android.app.AppOpsManager.OpEventProxyInfo;
Hai Zhang2b98fb32018-09-21 15:18:46 -070037import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
38import static android.app.AppOpsManager.UID_STATE_CACHED;
39import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
40import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
Svet Ganovaf189e32019-02-15 18:45:29 -080041import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
Hai Zhang2b98fb32018-09-21 15:18:46 -070042import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
43import static android.app.AppOpsManager.UID_STATE_TOP;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070044import static android.app.AppOpsManager._NUM_OP;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -080045import static android.app.AppOpsManager.extractFlagsFromKey;
46import static android.app.AppOpsManager.extractUidStateFromKey;
47import static android.app.AppOpsManager.makeKey;
Eugene Suslae4ee2c22018-11-05 12:23:30 -080048import static android.app.AppOpsManager.modeToName;
49import static android.app.AppOpsManager.opToName;
Svet Ganovaf189e32019-02-15 18:45:29 -080050import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080051import static android.content.Intent.ACTION_PACKAGE_REMOVED;
52import static android.content.Intent.EXTRA_REPLACING;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070053import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
Nate Myren697650b2020-01-23 13:25:06 -080054import static android.os.Process.STATSD_UID;
Hai Zhang2b98fb32018-09-21 15:18:46 -070055
Philip P. Moltmanne683f192017-06-23 14:05:04 -070056import android.Manifest;
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -080057import android.annotation.IntRange;
Svet Ganovad0a49b2018-10-29 10:07:08 -070058import android.annotation.NonNull;
59import android.annotation.Nullable;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070060import android.app.ActivityManager;
Nate Myren697650b2020-01-23 13:25:06 -080061import android.app.ActivityManagerInternal;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070062import android.app.ActivityThread;
63import android.app.AppGlobals;
64import android.app.AppOpsManager;
Svet Ganov8455ba22019-01-02 13:05:56 -080065import android.app.AppOpsManager.HistoricalOps;
Svet Ganovaf189e32019-02-15 18:45:29 -080066import android.app.AppOpsManager.Mode;
67import android.app.AppOpsManager.OpEntry;
Philip P. Moltmann02cd91b2019-11-05 14:29:52 -080068import android.app.AppOpsManager.OpFeatureEntry;
Svet Ganovaf189e32019-02-15 18:45:29 -080069import android.app.AppOpsManager.OpFlags;
Dianne Hackbornd5254412018-05-11 18:02:58 -070070import android.app.AppOpsManagerInternal;
Svet Ganovd873ae62018-06-25 16:39:23 -070071import android.app.AppOpsManagerInternal.CheckOpsDelegate;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070072import android.app.AsyncNotedAppOp;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080073import android.content.BroadcastReceiver;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070074import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070075import android.content.Context;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080076import android.content.Intent;
77import android.content.IntentFilter;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070078import android.content.pm.ApplicationInfo;
79import android.content.pm.IPackageManager;
80import android.content.pm.PackageManager;
81import android.content.pm.PackageManagerInternal;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070082import android.content.pm.PermissionInfo;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070083import android.content.pm.UserInfo;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080084import android.content.pm.parsing.AndroidPackage;
85import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070086import android.database.ContentObserver;
Yin-Chia Yeh51d85162019-08-06 15:31:39 -070087import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070088import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070089import android.os.AsyncTask;
90import android.os.Binder;
Hai Zhang408ca762019-10-14 14:09:35 -070091import android.os.Build;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070092import android.os.Bundle;
93import android.os.Handler;
94import android.os.IBinder;
95import android.os.Process;
Svet Ganov8455ba22019-01-02 13:05:56 -080096import android.os.RemoteCallback;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070097import android.os.RemoteCallbackList;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070098import android.os.RemoteException;
99import android.os.ResultReceiver;
100import android.os.ServiceManager;
101import android.os.ShellCallback;
102import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700103import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700104import android.os.UserHandle;
105import android.os.UserManager;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700106import android.os.storage.StorageManager;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700107import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700108import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700109import android.util.ArrayMap;
110import android.util.ArraySet;
111import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700112import android.util.KeyValueListParser;
Svet Ganovaf189e32019-02-15 18:45:29 -0800113import android.util.LongSparseArray;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700114import android.util.Pair;
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800115import android.util.Pools.SimplePool;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700116import android.util.Slog;
117import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700118import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700119import android.util.SparseIntArray;
120import android.util.TimeUtils;
121import android.util.Xml;
122
Todd Kennedy556efba2018-11-15 07:43:55 -0800123import com.android.internal.annotations.GuardedBy;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700124import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800125import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700126import com.android.internal.app.IAppOpsAsyncNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700127import com.android.internal.app.IAppOpsCallback;
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800128import com.android.internal.app.IAppOpsNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700129import com.android.internal.app.IAppOpsService;
130import com.android.internal.os.Zygote;
131import com.android.internal.util.ArrayUtils;
Hai Zhange53e4c52019-10-08 18:57:01 -0700132import com.android.internal.util.CollectionUtils;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700133import com.android.internal.util.DumpUtils;
134import com.android.internal.util.FastXmlSerializer;
135import com.android.internal.util.Preconditions;
136import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800137import com.android.internal.util.function.pooled.PooledLambda;
Svet Ganov8455ba22019-01-02 13:05:56 -0800138import com.android.server.LocalServices;
139import com.android.server.LockGuard;
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800140import com.android.server.SystemServerInitThreadPool;
Philip P. Moltmanndde07852019-01-25 16:42:36 -0800141
Philip P. Moltmann02cd91b2019-11-05 14:29:52 -0800142import libcore.util.EmptyArray;
143
144import org.xmlpull.v1.XmlPullParser;
145import org.xmlpull.v1.XmlPullParserException;
146import org.xmlpull.v1.XmlSerializer;
147
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800148import java.io.File;
149import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800150import java.io.FileInputStream;
151import java.io.FileNotFoundException;
152import java.io.FileOutputStream;
153import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800154import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100155import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700156import java.text.SimpleDateFormat;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800157import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700158import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -0700159import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700160import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800161import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800162import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800163import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700164import java.util.Map;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700165import java.util.Objects;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800166
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800167public class AppOpsService extends IAppOpsService.Stub {
168 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800169 static final boolean DEBUG = false;
170
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700171 private static final int NO_VERSION = -1;
172 /** Increment by one every time and add the corresponding upgrade logic in
173 * {@link #upgradeLocked(int)} below. The first version was 1 */
174 private static final int CURRENT_VERSION = 1;
175
Dianne Hackborn35654b62013-01-14 17:38:02 -0800176 // Write at most every 30 minutes.
177 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800178
Svet Ganov3a95f832018-03-23 17:44:30 -0700179 // Constant meaning that any UID should be matched when dispatching callbacks
180 private static final int UID_ANY = -2;
181
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700182 // Map from process states to the uid states we track.
183 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
184 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
185 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
186 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
Amith Yamasanif235d0b2019-03-20 22:49:43 -0700187 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_TOP
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700188 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
189 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
Hui Yu26969322019-08-21 14:56:35 -0700190 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700191 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
192 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
193 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
194 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
195 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
196 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
197 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
198 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
199 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
200 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
201 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
202 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
203 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
204 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
205 };
206
Suprabh Shukla7e017922019-08-05 17:13:23 -0700207 private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
208 OP_PLAY_AUDIO,
209 OP_RECORD_AUDIO,
210 OP_CAMERA,
211 };
212
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700213 private static final int MAX_UNFORWARED_OPS = 10;
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800214 private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700215
Hui Yu0620a332020-01-27 14:59:07 -0800216 //TODO: remove this when development is done.
217 private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;
218
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800219 Context mContext;
220 final AtomicFile mFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800221 final Handler mHandler;
222
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800223 /** Pool for {@link OpEventProxyInfoPool} to avoid to constantly reallocate new objects */
224 @GuardedBy("this")
225 private final OpEventProxyInfoPool mOpEventProxyInfoPool = new OpEventProxyInfoPool();
226
227 /** Pool for {@link InProgressStartOpEventPool} to avoid to constantly reallocate new objects */
228 @GuardedBy("this")
229 private final InProgressStartOpEventPool mInProgressStartOpEventPool =
230 new InProgressStartOpEventPool();
231
Dianne Hackbornd5254412018-05-11 18:02:58 -0700232 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
233 = new AppOpsManagerInternalImpl();
234
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700235 /**
Philip P. Moltmannda554e42019-12-20 11:21:02 -0800236 * Registered callbacks, called from {@link #collectAsyncNotedOp}.
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700237 *
238 * <p>(package name, uid) -> callbacks
239 *
240 * @see #getAsyncNotedOpsKey(String, int)
241 */
242 @GuardedBy("this")
243 private final ArrayMap<Pair<String, Integer>, RemoteCallbackList<IAppOpsAsyncNotedCallback>>
244 mAsyncOpWatchers = new ArrayMap<>();
245
246 /**
Philip P. Moltmannda554e42019-12-20 11:21:02 -0800247 * Async note-ops collected from {@link #collectAsyncNotedOp} that have not been delivered to a
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700248 * callback yet.
249 *
250 * <p>(package name, uid) -> list&lt;ops&gt;
251 *
252 * @see #getAsyncNotedOpsKey(String, int)
253 */
254 @GuardedBy("this")
255 private final ArrayMap<Pair<String, Integer>, ArrayList<AsyncNotedAppOp>>
256 mUnforwardedAsyncNotedOps = new ArrayMap<>();
257
Dianne Hackborn35654b62013-01-14 17:38:02 -0800258 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800259 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800260 final Runnable mWriteRunner = new Runnable() {
261 public void run() {
262 synchronized (AppOpsService.this) {
263 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800264 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800265 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
266 @Override protected Void doInBackground(Void... params) {
267 writeState();
268 return null;
269 }
270 };
271 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
272 }
273 }
274 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800275
Eugene Susla463d5922019-07-17 18:14:15 -0700276 @GuardedBy("this")
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700277 @VisibleForTesting
278 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800279
Svet Ganov47641072019-06-06 12:57:12 -0700280 final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
Svet Ganov8455ba22019-01-02 13:05:56 -0800281
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700282 long mLastRealtime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700283
Ruben Brunk29931bc2016-03-11 00:24:26 -0800284 /*
285 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800286 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700287 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400288
Dianne Hackbornd5254412018-05-11 18:02:58 -0700289 SparseIntArray mProfileOwners;
290
Todd Kennedy556efba2018-11-15 07:43:55 -0800291 @GuardedBy("this")
Svet Ganovd873ae62018-06-25 16:39:23 -0700292 private CheckOpsDelegate mCheckOpsDelegate;
293
Hai Zhange53e4c52019-10-08 18:57:01 -0700294 @GuardedBy("this")
295 private SparseArray<List<Integer>> mSwitchOpToOps;
296
Hui Yu88910de2019-12-16 14:35:27 -0800297 private ActivityManagerInternal mActivityManagerInternal;
298
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700299 /**
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800300 * An unsynchronized pool of {@link OpEventProxyInfo} objects.
301 */
302 private class OpEventProxyInfoPool extends SimplePool<OpEventProxyInfo> {
303 OpEventProxyInfoPool() {
304 super(MAX_UNUSED_POOLED_OBJECTS);
305 }
306
307 OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName,
308 @Nullable String featureId) {
309 OpEventProxyInfo recycled = acquire();
310 if (recycled != null) {
311 recycled.reinit(uid, packageName, featureId);
312 return recycled;
313 }
314
315 return new OpEventProxyInfo(uid, packageName, featureId);
316 }
317 }
318
319 /**
320 * An unsynchronized pool of {@link InProgressStartOpEvent} objects.
321 */
322 private class InProgressStartOpEventPool extends SimplePool<InProgressStartOpEvent> {
323 InProgressStartOpEventPool() {
324 super(MAX_UNUSED_POOLED_OBJECTS);
325 }
326
327 InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
328 @NonNull Runnable onDeath, int uidState) throws RemoteException {
329 InProgressStartOpEvent recycled = acquire();
330 if (recycled != null) {
331 recycled.reinit(startTime, elapsedTime, clientId, onDeath, uidState);
332 return recycled;
333 }
334
335 return new InProgressStartOpEvent(startTime, elapsedTime, clientId, onDeath, uidState);
336 }
337 }
338
339 /**
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700340 * All times are in milliseconds. These constants are kept synchronized with the system
341 * global Settings. Any access to this class or its fields should be done while
342 * holding the AppOpsService lock.
343 */
Amith Yamasani23d4cd72019-04-10 17:57:00 -0700344 @VisibleForTesting
345 final class Constants extends ContentObserver {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700346 // Key names stored in the settings value.
Dianne Hackborne93ab412018-05-14 17:52:30 -0700347 private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
348 private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
349 = "fg_service_state_settle_time";
350 private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700351
352 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700353 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700354 * @see Settings.Global#APP_OPS_CONSTANTS
Dianne Hackborne93ab412018-05-14 17:52:30 -0700355 * @see #KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700356 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700357 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700358
Dianne Hackborne93ab412018-05-14 17:52:30 -0700359 /**
360 * How long we want for a drop in uid state from foreground to settle before applying it.
361 * @see Settings.Global#APP_OPS_CONSTANTS
362 * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
363 */
364 public long FG_SERVICE_STATE_SETTLE_TIME;
365
366 /**
367 * How long we want for a drop in uid state from background to settle before applying it.
368 * @see Settings.Global#APP_OPS_CONSTANTS
369 * @see #KEY_BG_STATE_SETTLE_TIME
370 */
371 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700372
373 private final KeyValueListParser mParser = new KeyValueListParser(',');
374 private ContentResolver mResolver;
375
376 public Constants(Handler handler) {
377 super(handler);
378 updateConstants();
379 }
380
381 public void startMonitoring(ContentResolver resolver) {
382 mResolver = resolver;
383 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700384 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700385 false, this);
386 updateConstants();
387 }
388
389 @Override
390 public void onChange(boolean selfChange, Uri uri) {
391 updateConstants();
392 }
393
394 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700395 String value = mResolver != null ? Settings.Global.getString(mResolver,
396 Settings.Global.APP_OPS_CONSTANTS) : "";
397
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700398 synchronized (AppOpsService.this) {
399 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700400 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700401 } catch (IllegalArgumentException e) {
402 // Failed to parse the settings string, log this and move on
403 // with defaults.
404 Slog.e(TAG, "Bad app ops settings", e);
405 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700406 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
407 KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
408 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
409 KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
410 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
411 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700412 }
413 }
414
415 void dump(PrintWriter pw) {
416 pw.println(" Settings:");
417
Dianne Hackborne93ab412018-05-14 17:52:30 -0700418 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
419 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700420 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700421 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
422 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700423 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700424 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
425 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700426 pw.println();
427 }
428 }
429
Amith Yamasani23d4cd72019-04-10 17:57:00 -0700430 @VisibleForTesting
431 final Constants mConstants;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700432
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700433 @VisibleForTesting
Hui Yu88910de2019-12-16 14:35:27 -0800434 final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700435 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700436
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700437 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700438 public int pendingState = UID_STATE_CACHED;
439 public long pendingStateCommitTime;
Hui Yu26969322019-08-21 14:56:35 -0700440 public int capability;
441 public int pendingCapability;
Hui Yu88910de2019-12-16 14:35:27 -0800442 public boolean appWidgetVisible;
443 public boolean pendingAppWidgetVisible;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700444
Svet Ganov2af57082015-07-30 08:44:20 -0700445 public ArrayMap<String, Ops> pkgOps;
Hai Zhang93540ca2019-09-28 00:04:18 +0000446 public SparseIntArray opModes;
Svet Ganov2af57082015-07-30 08:44:20 -0700447
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700448 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700449 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700450 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700451
Hui Yu88910de2019-12-16 14:35:27 -0800452 public long lastTimeShowDebugToast;
453
Svet Ganov2af57082015-07-30 08:44:20 -0700454 public UidState(int uid) {
455 this.uid = uid;
456 }
457
458 public void clear() {
459 pkgOps = null;
460 opModes = null;
461 }
462
463 public boolean isDefault() {
464 return (pkgOps == null || pkgOps.isEmpty())
Svet Ganovaf189e32019-02-15 18:45:29 -0800465 && (opModes == null || opModes.size() <= 0)
466 && (state == UID_STATE_CACHED
467 && (pendingState == UID_STATE_CACHED));
Svet Ganov2af57082015-07-30 08:44:20 -0700468 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700469
Svet Ganovaf189e32019-02-15 18:45:29 -0800470 int evalMode(int op, int mode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700471 if (mode == AppOpsManager.MODE_FOREGROUND) {
Hui Yu88910de2019-12-16 14:35:27 -0800472 if (appWidgetVisible) {
473 return MODE_ALLOWED;
474 } else if (state <= UID_STATE_TOP) {
Hui Yu26969322019-08-21 14:56:35 -0700475 // process is in foreground.
476 return AppOpsManager.MODE_ALLOWED;
477 } else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) {
478 // process is in foreground, check its capability.
479 switch (op) {
480 case AppOpsManager.OP_FINE_LOCATION:
481 case AppOpsManager.OP_COARSE_LOCATION:
482 case AppOpsManager.OP_MONITOR_LOCATION:
483 case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
Hui Yu88910de2019-12-16 14:35:27 -0800484 if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
485 return AppOpsManager.MODE_ALLOWED;
Hui Yu0620a332020-01-27 14:59:07 -0800486 } else if ((capability
487 & TEMP_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
488 // The FGS has the location capability, but due to FGS BG start
489 // restriction it lost the capability, use temp location capability
490 // to mark this case.
491 // TODO change to MODE_IGNORED when enforcing the feature.
Hui Yu88910de2019-12-16 14:35:27 -0800492 maybeShowWhileInUseDebugToast(op, mode);
Hui Yu0620a332020-01-27 14:59:07 -0800493 return AppOpsManager.MODE_ALLOWED;
494 } else {
Hui Yu88910de2019-12-16 14:35:27 -0800495 return AppOpsManager.MODE_IGNORED;
496 }
Hui Yu85679b42020-01-15 15:52:08 -0800497 case OP_CAMERA:
Hui Yu88910de2019-12-16 14:35:27 -0800498 if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
499 return AppOpsManager.MODE_ALLOWED;
500 } else {
501 //TODO change to MODE_IGNORED when enforcing the feature.
502 maybeShowWhileInUseDebugToast(op, mode);
503 return AppOpsManager.MODE_ALLOWED;
504 }
Hui Yu85679b42020-01-15 15:52:08 -0800505 case OP_RECORD_AUDIO:
Hui Yu88910de2019-12-16 14:35:27 -0800506 if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
507 return AppOpsManager.MODE_ALLOWED;
508 } else {
509 //TODO change to MODE_IGNORED when enforcing the feature.
510 maybeShowWhileInUseDebugToast(op, mode);
511 return AppOpsManager.MODE_ALLOWED;
512 }
Hui Yu26969322019-08-21 14:56:35 -0700513 default:
514 return AppOpsManager.MODE_ALLOWED;
515 }
516 } else {
517 // process is not in foreground.
518 return AppOpsManager.MODE_IGNORED;
519 }
Hui Yu88910de2019-12-16 14:35:27 -0800520 } else if (mode == AppOpsManager.MODE_ALLOWED) {
521 switch (op) {
522 case OP_CAMERA:
523 if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
524 return AppOpsManager.MODE_ALLOWED;
525 } else {
526 //TODO change to MODE_IGNORED when enforcing the feature.
527 maybeShowWhileInUseDebugToast(op, mode);
528 return AppOpsManager.MODE_ALLOWED;
529 }
530 case OP_RECORD_AUDIO:
531 if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
532 return AppOpsManager.MODE_ALLOWED;
533 } else {
534 //TODO change to MODE_IGNORED when enforcing the feature.
535 maybeShowWhileInUseDebugToast(op, mode);
536 return AppOpsManager.MODE_ALLOWED;
537 }
538 default:
539 return MODE_ALLOWED;
540 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700541 }
542 return mode;
543 }
544
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700545 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
546 SparseBooleanArray which) {
547 boolean curValue = which.get(op, false);
548 ArraySet<ModeCallback> callbacks = watchers.get(op);
549 if (callbacks != null) {
550 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
551 if ((callbacks.valueAt(cbi).mFlags
552 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
553 hasForegroundWatchers = true;
554 curValue = true;
555 }
556 }
557 }
558 which.put(op, curValue);
559 }
560
561 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700562 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700563 hasForegroundWatchers = false;
Hai Zhang93540ca2019-09-28 00:04:18 +0000564 if (opModes != null) {
565 for (int i = opModes.size() - 1; i >= 0; i--) {
566 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
567 if (which == null) {
568 which = new SparseBooleanArray();
569 }
570 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700571 }
572 }
573 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700574 if (pkgOps != null) {
575 for (int i = pkgOps.size() - 1; i >= 0; i--) {
576 Ops ops = pkgOps.valueAt(i);
577 for (int j = ops.size() - 1; j >= 0; j--) {
578 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
579 if (which == null) {
580 which = new SparseBooleanArray();
581 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700582 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700583 }
584 }
585 }
586 }
587 foregroundOps = which;
588 }
Hui Yu88910de2019-12-16 14:35:27 -0800589
590 // TODO: remove this toast after feature development is done
591 // If the procstate is foreground service and while-in-use permission is denied, show a
592 // toast message to ask user to file a bugreport so we know how many apps are impacted by
593 // the new background started foreground service while-in-use permission restriction.
594 void maybeShowWhileInUseDebugToast(int op, int mode) {
595 if (state != UID_STATE_FOREGROUND_SERVICE) {
596 return;
597 }
598 final long now = System.currentTimeMillis();
Hui Yu0620a332020-01-27 14:59:07 -0800599 if (lastTimeShowDebugToast == 0 || now - lastTimeShowDebugToast > 3600000) {
Hui Yu88910de2019-12-16 14:35:27 -0800600 lastTimeShowDebugToast = now;
601 mHandler.sendMessage(PooledLambda.obtainMessage(
602 ActivityManagerInternal::showWhileInUseDebugToast,
603 mActivityManagerInternal, uid, op, mode));
604 }
605 }
Svet Ganov2af57082015-07-30 08:44:20 -0700606 }
607
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700608 final static class Ops extends SparseArray<Op> {
609 final String packageName;
610 final UidState uidState;
611 final boolean isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800612
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800613 /** Lazily populated cache of featureIds of this package */
614 final @NonNull ArraySet<String> knownFeatureIds = new ArraySet<>();
615
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700616 Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800617 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700618 uidState = _uidState;
Jason Monk1c7c3192014-06-26 12:52:18 -0400619 isPrivileged = _isPrivileged;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800620 }
621 }
622
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800623 /** A in progress startOp->finishOp event */
624 private static final class InProgressStartOpEvent implements IBinder.DeathRecipient {
Philip P. Moltmanne6ece902020-01-02 13:31:10 -0800625 /** Wall clock time of startOp event (not monotonic) */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800626 private long mStartTime;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800627
Philip P. Moltmanne6ece902020-01-02 13:31:10 -0800628 /** Elapsed time since boot of startOp event */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800629 private long mStartElapsedTime;
Philip P. Moltmanne6ece902020-01-02 13:31:10 -0800630
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800631 /** Id of the client that started the event */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800632 private @NonNull IBinder mClientId;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800633
634 /** To call when client dies */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800635 private @NonNull Runnable mOnDeath;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800636
637 /** uidstate used when calling startOp */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800638 private @AppOpsManager.UidState int mUidState;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800639
640 /** How many times the op was started but not finished yet */
641 int numUnfinishedStarts;
642
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800643 /**
644 * Create a new {@link InProgressStartOpEvent}.
645 *
646 * @param startTime The time {@link #startOperation} was called
647 * @param startElapsedTime The elapsed time when {@link #startOperation} was called
648 * @param clientId The client id of the caller of {@link #startOperation}
649 * @param onDeath The code to execute on client death
650 * @param uidState The uidstate of the app {@link #startOperation} was called for
651 *
652 * @throws RemoteException If the client is dying
653 */
Philip P. Moltmanne6ece902020-01-02 13:31:10 -0800654 private InProgressStartOpEvent(long startTime, long startElapsedTime,
655 @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState)
656 throws RemoteException {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800657 mStartTime = startTime;
658 mStartElapsedTime = startElapsedTime;
659 mClientId = clientId;
660 mOnDeath = onDeath;
661 mUidState = uidState;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800662
663 clientId.linkToDeath(this, 0);
664 }
665
666 /** Clean up event */
667 public void finish() {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800668 mClientId.unlinkToDeath(this, 0);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800669 }
670
671 @Override
672 public void binderDied() {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800673 mOnDeath.run();
674 }
675
676 /**
677 * Reinit existing object with new state.
678 *
679 * @param startTime The time {@link #startOperation} was called
680 * @param startElapsedTime The elapsed time when {@link #startOperation} was called
681 * @param clientId The client id of the caller of {@link #startOperation}
682 * @param onDeath The code to execute on client death
683 * @param uidState The uidstate of the app {@link #startOperation} was called for
684 *
685 * @throws RemoteException If the client is dying
686 */
687 public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId,
688 @NonNull Runnable onDeath, int uidState) throws RemoteException {
689 mStartTime = startTime;
690 mStartElapsedTime = startElapsedTime;
691 mClientId = clientId;
692 mOnDeath = onDeath;
693 mUidState = uidState;
694
695 clientId.linkToDeath(this, 0);
696 }
697
698 /** @return Wall clock time of startOp event */
699 public long getStartTime() {
700 return mStartTime;
701 }
702
703 /** @return Elapsed time since boot of startOp event */
704 public long getStartElapsedTime() {
705 return mStartElapsedTime;
706 }
707
708 /** @return Id of the client that started the event */
709 public @NonNull IBinder getClientId() {
710 return mClientId;
711 }
712
713 /** @return uidstate used when calling startOp */
714 public int getUidState() {
715 return mUidState;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800716 }
717 }
718
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800719 private final class FeatureOp {
Philip P. Moltmann4aacd712020-01-03 12:32:20 -0800720 public final @Nullable String featureId;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700721 public final @NonNull Op parent;
Svet Ganovaf189e32019-02-15 18:45:29 -0800722
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800723 /**
724 * Last successful accesses (noteOp + finished startOp) for each uidState/opFlag combination
725 *
726 * <p>Key is {@link AppOpsManager#makeKey}
727 */
728 @GuardedBy("AppOpsService.this")
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800729 private @Nullable LongSparseArray<NoteOpEvent> mAccessEvents;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800730
731 /**
732 * Last rejected accesses for each uidState/opFlag combination
733 *
734 * <p>Key is {@link AppOpsManager#makeKey}
735 */
736 @GuardedBy("AppOpsService.this")
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800737 private @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
Svet Ganovaf189e32019-02-15 18:45:29 -0800738
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800739 /**
740 * Currently in progress startOp events
741 *
742 * <p>Key is clientId
743 */
744 @GuardedBy("AppOpsService.this")
745 private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mInProgressEvents;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700746
Philip P. Moltmann4aacd712020-01-03 12:32:20 -0800747 FeatureOp(@Nullable String featureId, @NonNull Op parent) {
748 this.featureId = featureId;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700749 this.parent = parent;
750 }
751
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800752 /**
753 * Update state when noteOp was rejected or startOp->finishOp event finished
754 *
755 * @param proxyUid The uid of the proxy
756 * @param proxyPackageName The package name of the proxy
757 * @param proxyFeatureId the featureId in the proxies package
758 * @param uidState UID state of the app noteOp/startOp was called for
759 * @param flags OpFlags of the call
760 */
761 public void accessed(int proxyUid, @Nullable String proxyPackageName,
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700762 @Nullable String proxyFeatureId, @AppOpsManager.UidState int uidState,
763 @OpFlags int flags) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800764 accessed(System.currentTimeMillis(), -1, proxyUid, proxyPackageName,
765 proxyFeatureId, uidState, flags);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -0800766
767 mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
768 featureId, uidState, flags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700769 }
770
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800771 /**
772 * Add an access that was previously collected.
773 *
774 * @param noteTime The time of the event
775 * @param duration The duration of the event
776 * @param proxyUid The uid of the proxy
777 * @param proxyPackageName The package name of the proxy
778 * @param proxyFeatureId the featureId in the proxies package
779 * @param uidState UID state of the app noteOp/startOp was called for
780 * @param flags OpFlags of the call
781 */
782 public void accessed(long noteTime, long duration, int proxyUid,
783 @Nullable String proxyPackageName, @Nullable String proxyFeatureId,
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700784 @AppOpsManager.UidState int uidState, @OpFlags int flags) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800785 long key = makeKey(uidState, flags);
786
787 if (mAccessEvents == null) {
788 mAccessEvents = new LongSparseArray<>(1);
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700789 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800790
791 OpEventProxyInfo proxyInfo = null;
792 if (proxyUid != Process.INVALID_UID) {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800793 proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
794 proxyFeatureId);
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700795 }
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800796
797 NoteOpEvent existingEvent = mAccessEvents.get(key);
798 if (existingEvent != null) {
799 existingEvent.reinit(noteTime, duration, proxyInfo, mOpEventProxyInfoPool);
800 } else {
801 mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo));
802 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700803 }
804
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800805 /**
806 * Update state when noteOp/startOp was rejected.
807 *
808 * @param uidState UID state of the app noteOp is called for
809 * @param flags OpFlags of the call
810 */
811 public void rejected(@AppOpsManager.UidState int uidState, @OpFlags int flags) {
812 rejected(System.currentTimeMillis(), uidState, flags);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -0800813
814 mHistoricalRegistry.incrementOpRejected(parent.op, parent.uid, parent.packageName,
815 featureId, uidState, flags);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800816 }
817
818 /**
819 * Add an rejection that was previously collected
820 *
821 * @param noteTime The time of the event
822 * @param uidState UID state of the app noteOp/startOp was called for
823 * @param flags OpFlags of the call
824 */
825 public void rejected(long noteTime, @AppOpsManager.UidState int uidState,
826 @OpFlags int flags) {
827 long key = makeKey(uidState, flags);
828
829 if (mRejectEvents == null) {
830 mRejectEvents = new LongSparseArray<>(1);
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700831 }
832
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800833 // We do not collect proxy information for rejections yet
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800834 NoteOpEvent existingEvent = mRejectEvents.get(key);
835 if (existingEvent != null) {
836 existingEvent.reinit(noteTime, -1, null, mOpEventProxyInfoPool);
837 } else {
838 mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null));
839 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800840 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700841
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800842 /**
843 * Update state when start was called
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800844 *
845 * @param clientId Id of the startOp caller
846 * @param uidState UID state of the app startOp is called for
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800847 */
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800848 public void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState)
849 throws RemoteException {
850 if (!parent.isRunning()) {
851 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
852 parent.packageName, true);
853 }
854
855 if (mInProgressEvents == null) {
856 mInProgressEvents = new ArrayMap<>(1);
857 }
858
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800859 InProgressStartOpEvent event = mInProgressEvents.get(clientId);
860 if (event == null) {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800861 event = mInProgressStartOpEventPool.acquire(System.currentTimeMillis(),
862 SystemClock.elapsedRealtime(), clientId,
863 PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
864 uidState);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800865 mInProgressEvents.put(clientId, event);
866 } else {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800867 if (uidState != event.mUidState) {
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800868 onUidStateChanged(uidState);
869 }
870 }
871
872 event.numUnfinishedStarts++;
873
874 // startOp events don't support proxy, hence use flags==SELF
875 mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
Philip P. Moltmann4aacd712020-01-03 12:32:20 -0800876 featureId, uidState, OP_FLAG_SELF);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800877 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700878
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800879 /**
880 * Update state when finishOp was called
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800881 *
882 * @param clientId Id of the finishOp caller
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800883 */
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800884 public void finished(@NonNull IBinder clientId) {
885 finished(clientId, true);
886 }
887
888 private void finished(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded) {
889 if (mInProgressEvents == null) {
890 Slog.wtf(TAG, "No ops running");
891 return;
892 }
893
894 int indexOfToken = mInProgressEvents.indexOfKey(clientId);
895 if (indexOfToken < 0) {
896 Slog.wtf(TAG, "No op running for the client");
897 return;
898 }
899
900 InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken);
901 event.numUnfinishedStarts--;
902 if (event.numUnfinishedStarts == 0) {
903 event.finish();
904 mInProgressEvents.removeAt(indexOfToken);
905
906 if (mAccessEvents == null) {
907 mAccessEvents = new LongSparseArray<>(1);
908 }
909
910 // startOp events don't support proxy, hence use flags==SELF
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800911 NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(),
912 SystemClock.elapsedRealtime() - event.getStartElapsedTime(), null);
913 mAccessEvents.put(makeKey(event.getUidState(), OP_FLAG_SELF), finishedEvent);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800914
915 mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
Philip P. Moltmann4aacd712020-01-03 12:32:20 -0800916 parent.packageName, featureId, event.getUidState(),
917 AppOpsManager.OP_FLAG_SELF, finishedEvent.getDuration());
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800918
919 mInProgressStartOpEventPool.release(event);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800920
921 if (mInProgressEvents.isEmpty()) {
922 mInProgressEvents = null;
923
924 // TODO moltmann: Also callback for single feature activity changes
925 if (triggerCallbackIfNeeded && !parent.isRunning()) {
926 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
927 parent.packageName, false);
928 }
929 }
930 }
931 }
932
933 /**
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800934 * Called in the case the client dies without calling finish first
935 *
936 * @param clientId The client that died
937 */
938 void onClientDeath(@NonNull IBinder clientId) {
939 synchronized (AppOpsService.this) {
940 if (mInProgressEvents == null) {
941 return;
942 }
943
944 InProgressStartOpEvent deadEvent = mInProgressEvents.get(clientId);
945 if (deadEvent != null) {
946 deadEvent.numUnfinishedStarts = 1;
947 }
948
949 finished(clientId);
950 }
951 }
952
953 /**
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800954 * Notify that the state of the uid changed
955 *
956 * @param newState The new state
957 */
958 public void onUidStateChanged(@AppOpsManager.UidState int newState) {
959 if (mInProgressEvents == null) {
960 return;
961 }
962
963 int numInProgressEvents = mInProgressEvents.size();
964 for (int i = 0; i < numInProgressEvents; i++) {
965 InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
966
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800967 if (event.getUidState() != newState) {
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800968 try {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800969 finished(event.getClientId(), false);
970 started(event.getClientId(), newState);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800971 } catch (RemoteException e) {
972 if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
973 }
974 }
975 }
976 }
977
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800978 /**
979 * Combine {@code a} and {@code b} and return the result. The result might be {@code a}
980 * or {@code b}. If there is an event for the same key in both the later event is retained.
981 */
982 private @Nullable LongSparseArray<NoteOpEvent> add(@Nullable LongSparseArray<NoteOpEvent> a,
983 @Nullable LongSparseArray<NoteOpEvent> b) {
984 if (a == null) {
985 return b;
986 }
987
988 if (b == null) {
989 return a;
990 }
991
992 int numEventsToAdd = b.size();
993 for (int i = 0; i < numEventsToAdd; i++) {
994 long keyOfEventToAdd = b.keyAt(i);
995 NoteOpEvent bEvent = b.valueAt(i);
996 NoteOpEvent aEvent = a.get(keyOfEventToAdd);
997
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800998 if (aEvent == null || bEvent.getNoteTime() > aEvent.getNoteTime()) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800999 a.put(keyOfEventToAdd, bEvent);
1000 }
1001 }
1002
1003 return a;
1004 }
1005
1006 /**
1007 * Add all data from the {@code featureToAdd} to this op.
1008 *
1009 * <p>If there is an event for the same key in both the later event is retained.
1010 * <p>{@code opToAdd} should not be used after this method is called.
1011 *
1012 * @param opToAdd The op to add
1013 */
1014 public void add(@NonNull FeatureOp opToAdd) {
1015 if (opToAdd.mInProgressEvents != null) {
1016 Slog.w(TAG, "Ignoring " + opToAdd.mInProgressEvents.size() + " running app-ops");
1017
1018 int numInProgressEvents = opToAdd.mInProgressEvents.size();
1019 for (int i = 0; i < numInProgressEvents; i++) {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001020 InProgressStartOpEvent event = opToAdd.mInProgressEvents.valueAt(i);
1021
1022 event.finish();
1023 mInProgressStartOpEventPool.release(event);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001024 }
1025 }
1026
1027 mAccessEvents = add(mAccessEvents, opToAdd.mAccessEvents);
1028 mRejectEvents = add(mRejectEvents, opToAdd.mRejectEvents);
1029 }
1030
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001031 public boolean isRunning() {
1032 return mInProgressEvents != null;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001033 }
1034
1035 boolean hasAnyTime() {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001036 return (mAccessEvents != null && mAccessEvents.size() > 0)
1037 || (mRejectEvents != null && mRejectEvents.size() > 0);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001038 }
1039
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001040 /**
1041 * Clone a {@link LongSparseArray} and clone all values.
1042 */
1043 private @Nullable LongSparseArray<NoteOpEvent> deepClone(
1044 @Nullable LongSparseArray<NoteOpEvent> original) {
1045 if (original == null) {
1046 return original;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001047 }
1048
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001049 int size = original.size();
1050 LongSparseArray<NoteOpEvent> clone = new LongSparseArray<>(size);
1051 for (int i = 0; i < size; i++) {
1052 clone.put(original.keyAt(i), new NoteOpEvent(original.valueAt(i)));
1053 }
1054
1055 return clone;
1056 }
1057
1058 @NonNull OpFeatureEntry createFeatureEntryLocked() {
1059 LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents);
1060
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001061 // Add in progress events as access events
1062 if (mInProgressEvents != null) {
Philip P. Moltmanne6ece902020-01-02 13:31:10 -08001063 long now = SystemClock.elapsedRealtime();
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001064 int numInProgressEvents = mInProgressEvents.size();
1065
1066 if (accessEvents == null) {
1067 accessEvents = new LongSparseArray<>(numInProgressEvents);
1068 }
1069
1070 for (int i = 0; i < numInProgressEvents; i++) {
1071 InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
1072
1073 // startOp events don't support proxy
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001074 accessEvents.append(makeKey(event.getUidState(), OP_FLAG_SELF),
1075 new NoteOpEvent(event.getStartTime(), now - event.getStartElapsedTime(),
1076 null));
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001077 }
1078 }
1079
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001080 LongSparseArray<NoteOpEvent> rejectEvents = deepClone(mRejectEvents);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001081
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001082 return new OpFeatureEntry(parent.op, isRunning(), accessEvents, rejectEvents);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001083 }
1084 }
1085
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001086 final class Op {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001087 int op;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001088 int uid;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001089 final UidState uidState;
1090 final @NonNull String packageName;
1091
1092 private @Mode int mode;
1093
1094 /** featureId -> FeatureOp */
1095 final ArrayMap<String, FeatureOp> mFeatures = new ArrayMap<>(1);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001096
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001097 Op(UidState uidState, String packageName, int op, int uid) {
Svet Ganovaf189e32019-02-15 18:45:29 -08001098 this.op = op;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001099 this.uid = uid;
Svet Ganovaf189e32019-02-15 18:45:29 -08001100 this.uidState = uidState;
1101 this.packageName = packageName;
1102 this.mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001103 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001104
1105 int getMode() {
Svet Ganovaf189e32019-02-15 18:45:29 -08001106 return mode;
1107 }
1108
1109 int evalMode() {
1110 return uidState.evalMode(op, mode);
1111 }
1112
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001113 void removeFeaturesWithNoTime() {
1114 for (int i = mFeatures.size() - 1; i >= 0; i--) {
1115 if (!mFeatures.valueAt(i).hasAnyTime()) {
1116 mFeatures.removeAt(i);
1117 }
Svet Ganovaf189e32019-02-15 18:45:29 -08001118 }
1119 }
1120
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001121 private @NonNull FeatureOp getOrCreateFeature(@NonNull Op parent,
1122 @Nullable String featureId) {
1123 FeatureOp featureOp;
1124
1125 featureOp = mFeatures.get(featureId);
1126 if (featureOp == null) {
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08001127 featureOp = new FeatureOp(featureId, parent);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001128 mFeatures.put(featureId, featureOp);
Svet Ganovaf189e32019-02-15 18:45:29 -08001129 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001130
1131 return featureOp;
Svet Ganovaf189e32019-02-15 18:45:29 -08001132 }
1133
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001134 @NonNull OpEntry createEntryLocked() {
1135 final int numFeatures = mFeatures.size();
Svet Ganovaf189e32019-02-15 18:45:29 -08001136
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001137 final ArrayMap<String, OpFeatureEntry> featureEntries = new ArrayMap<>(numFeatures);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001138 for (int i = 0; i < numFeatures; i++) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001139 featureEntries.put(mFeatures.keyAt(i),
1140 mFeatures.valueAt(i).createFeatureEntryLocked());
Philip P. Moltmann4052d362019-09-19 14:52:38 -07001141 }
1142
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001143 return new OpEntry(op, mode, featureEntries);
Svet Ganovaf189e32019-02-15 18:45:29 -08001144 }
1145
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001146 @NonNull OpEntry createSingleFeatureEntryLocked(@Nullable String featureId) {
1147 final int numFeatures = mFeatures.size();
1148
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001149 final ArrayMap<String, OpFeatureEntry> featureEntries = new ArrayMap<>(1);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001150 for (int i = 0; i < numFeatures; i++) {
1151 if (Objects.equals(mFeatures.keyAt(i), featureId)) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001152 featureEntries.put(mFeatures.keyAt(i),
1153 mFeatures.valueAt(i).createFeatureEntryLocked());
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001154 break;
1155 }
1156 }
1157
1158 return new OpEntry(op, mode, featureEntries);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001159 }
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001160
1161 boolean isRunning() {
1162 final int numFeatures = mFeatures.size();
1163 for (int i = 0; i < numFeatures; i++) {
1164 if (mFeatures.valueAt(i).isRunning()) {
1165 return true;
1166 }
1167 }
1168
1169 return false;
1170 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001171 }
1172
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001173 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
1174 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
1175 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
1176 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001177 final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07001178 final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001179
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001180 final class ModeCallback implements DeathRecipient {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001181 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001182 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001183 final int mFlags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001184 final int mCallingUid;
1185 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001186
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001187 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001188 int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001189 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001190 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001191 mFlags = flags;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001192 mCallingUid = callingUid;
1193 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001194 try {
1195 mCallback.asBinder().linkToDeath(this, 0);
1196 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001197 /*ignored*/
Dianne Hackbornc2293022013-02-06 23:14:49 -08001198 }
1199 }
1200
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001201 public boolean isWatchingUid(int uid) {
1202 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
1203 }
1204
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001205 @Override
1206 public String toString() {
1207 StringBuilder sb = new StringBuilder(128);
1208 sb.append("ModeCallback{");
1209 sb.append(Integer.toHexString(System.identityHashCode(this)));
1210 sb.append(" watchinguid=");
1211 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001212 sb.append(" flags=0x");
1213 sb.append(Integer.toHexString(mFlags));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001214 sb.append(" from uid=");
1215 UserHandle.formatUid(sb, mCallingUid);
1216 sb.append(" pid=");
1217 sb.append(mCallingPid);
1218 sb.append('}');
1219 return sb.toString();
1220 }
1221
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001222 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001223 mCallback.asBinder().unlinkToDeath(this, 0);
1224 }
1225
1226 @Override
1227 public void binderDied() {
1228 stopWatchingMode(mCallback);
1229 }
1230 }
1231
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001232 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001233 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001234 final int mWatchingUid;
1235 final int mCallingUid;
1236 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001237
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001238 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001239 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001240 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001241 mWatchingUid = watchingUid;
1242 mCallingUid = callingUid;
1243 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001244 try {
1245 mCallback.asBinder().linkToDeath(this, 0);
1246 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001247 /*ignored*/
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001248 }
1249 }
1250
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001251 @Override
1252 public String toString() {
1253 StringBuilder sb = new StringBuilder(128);
1254 sb.append("ActiveCallback{");
1255 sb.append(Integer.toHexString(System.identityHashCode(this)));
1256 sb.append(" watchinguid=");
1257 UserHandle.formatUid(sb, mWatchingUid);
1258 sb.append(" from uid=");
1259 UserHandle.formatUid(sb, mCallingUid);
1260 sb.append(" pid=");
1261 sb.append(mCallingPid);
1262 sb.append('}');
1263 return sb.toString();
1264 }
1265
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001266 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001267 mCallback.asBinder().unlinkToDeath(this, 0);
1268 }
1269
1270 @Override
1271 public void binderDied() {
1272 stopWatchingActive(mCallback);
1273 }
1274 }
1275
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001276 final class NotedCallback implements DeathRecipient {
1277 final IAppOpsNotedCallback mCallback;
1278 final int mWatchingUid;
1279 final int mCallingUid;
1280 final int mCallingPid;
1281
1282 NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
1283 int callingPid) {
1284 mCallback = callback;
1285 mWatchingUid = watchingUid;
1286 mCallingUid = callingUid;
1287 mCallingPid = callingPid;
1288 try {
1289 mCallback.asBinder().linkToDeath(this, 0);
1290 } catch (RemoteException e) {
1291 /*ignored*/
1292 }
1293 }
1294
1295 @Override
1296 public String toString() {
1297 StringBuilder sb = new StringBuilder(128);
1298 sb.append("NotedCallback{");
1299 sb.append(Integer.toHexString(System.identityHashCode(this)));
1300 sb.append(" watchinguid=");
1301 UserHandle.formatUid(sb, mWatchingUid);
1302 sb.append(" from uid=");
1303 UserHandle.formatUid(sb, mCallingUid);
1304 sb.append(" pid=");
1305 sb.append(mCallingPid);
1306 sb.append('}');
1307 return sb.toString();
1308 }
1309
1310 void destroy() {
1311 mCallback.asBinder().unlinkToDeath(this, 0);
1312 }
1313
1314 @Override
1315 public void binderDied() {
1316 stopWatchingNoted(mCallback);
1317 }
1318 }
1319
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001320 /**
1321 * Call {@link FeatureOp#onClientDeath featureOp.onClientDeath(clientId)}.
1322 */
1323 private static void onClientDeath(@NonNull FeatureOp featureOp, @NonNull IBinder clientId) {
1324 featureOp.onClientDeath(clientId);
1325 }
1326
Jeff Brown6f357d32014-01-15 20:40:55 -08001327 public AppOpsService(File storagePath, Handler handler) {
Jeff Sharkey5f3e9342017-03-13 14:53:11 -06001328 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -08001329 mFile = new AtomicFile(storagePath, "appops");
Jeff Brown6f357d32014-01-15 20:40:55 -08001330 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001331 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001332 readState();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001333 }
David Braunf5d83192013-09-16 13:43:51 -07001334
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001335 public void publish(Context context) {
1336 mContext = context;
1337 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -07001338 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001339 }
1340
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001341 /** Handler for work when packages are removed or updated */
1342 private BroadcastReceiver mOnPackageUpdatedReceiver = new BroadcastReceiver() {
1343 @Override
1344 public void onReceive(Context context, Intent intent) {
1345 String action = intent.getAction();
1346 String pkgName = intent.getData().getEncodedSchemeSpecificPart();
1347 int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
1348
1349 if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
1350 synchronized (AppOpsService.this) {
1351 UidState uidState = mUidStates.get(uid);
1352 if (uidState == null || uidState.pkgOps == null) {
1353 return;
1354 }
1355
1356 Ops removedOps = uidState.pkgOps.remove(pkgName);
1357 if (removedOps != null) {
1358 scheduleFastWriteLocked();
1359 }
1360 }
1361 } else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
1362 AndroidPackage pkg = LocalServices.getService(
1363 PackageManagerInternal.class).getPackage(pkgName);
1364 if (pkg == null) {
1365 return;
1366 }
1367
1368 ArrayMap<String, String> dstFeatureIds = new ArrayMap<>();
1369 ArraySet<String> featureIds = new ArraySet<>();
1370 if (pkg.getFeatures() != null) {
1371 int numFeatures = pkg.getFeatures().size();
1372 for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
1373 ParsedFeature feature = pkg.getFeatures().get(featureNum);
1374 featureIds.add(feature.id);
1375
1376 int numInheritFrom = feature.inheritFrom.size();
1377 for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
1378 inheritFromNum++) {
1379 dstFeatureIds.put(feature.inheritFrom.get(inheritFromNum),
1380 feature.id);
1381 }
1382 }
1383 }
1384
1385 synchronized (AppOpsService.this) {
1386 UidState uidState = mUidStates.get(uid);
1387 if (uidState == null || uidState.pkgOps == null) {
1388 return;
1389 }
1390
1391 Ops ops = uidState.pkgOps.get(pkgName);
1392 if (ops == null) {
1393 return;
1394 }
1395
1396 ops.knownFeatureIds.clear();
1397 int numOps = ops.size();
1398 for (int opNum = 0; opNum < numOps; opNum++) {
1399 Op op = ops.valueAt(opNum);
1400
1401 int numFeatures = op.mFeatures.size();
1402 for (int featureNum = numFeatures - 1; featureNum >= 0; featureNum--) {
1403 String featureId = op.mFeatures.keyAt(featureNum);
1404
1405 if (featureIds.contains(featureId)) {
1406 // feature still exist after upgrade
1407 continue;
1408 }
1409
1410 String newFeatureId = dstFeatureIds.get(featureId);
1411
1412 FeatureOp newFeatureOp = op.getOrCreateFeature(op, newFeatureId);
1413 newFeatureOp.add(op.mFeatures.valueAt(featureNum));
1414 op.mFeatures.removeAt(featureNum);
1415
1416 scheduleFastWriteLocked();
1417 }
1418 }
1419 }
1420 }
1421 }
1422 };
1423
Dianne Hackborn514074f2013-02-11 10:52:46 -08001424 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -07001425 mConstants.startMonitoring(mContext.getContentResolver());
Svet Ganov8455ba22019-01-02 13:05:56 -08001426 mHistoricalRegistry.systemReady(mContext.getContentResolver());
Dianne Hackborn45c79b02018-05-11 09:46:13 -07001427
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001428 IntentFilter packageUpdateFilter = new IntentFilter();
1429 packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1430 packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
1431 packageUpdateFilter.addDataScheme("package");
Svet Ganov2af57082015-07-30 08:44:20 -07001432
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001433 mContext.registerReceiver(mOnPackageUpdatedReceiver, packageUpdateFilter);
1434
1435 synchronized (this) {
1436 for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
1437 int uid = mUidStates.keyAt(uidNum);
1438 UidState uidState = mUidStates.valueAt(uidNum);
1439
1440 String[] pkgsInUid = getPackagesForUid(uidState.uid);
1441 if (ArrayUtils.isEmpty(pkgsInUid)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001442 uidState.clear();
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001443 mUidStates.removeAt(uidNum);
1444 scheduleFastWriteLocked();
Svet Ganov2af57082015-07-30 08:44:20 -07001445 continue;
1446 }
1447
1448 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
1449 if (pkgs == null) {
1450 continue;
1451 }
1452
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001453 int numPkgs = pkgs.size();
1454 for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
1455 String pkg = pkgs.keyAt(pkgNum);
Svet Ganov2af57082015-07-30 08:44:20 -07001456
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001457 String action;
1458 if (!ArrayUtils.contains(pkgsInUid, pkg)) {
1459 action = Intent.ACTION_PACKAGE_REMOVED;
1460 } else {
1461 action = Intent.ACTION_PACKAGE_REPLACED;
1462 }
1463
1464 SystemServerInitThreadPool.submit(
1465 () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
1466 .setData(Uri.fromParts("package", pkg, null))
1467 .putExtra(Intent.EXTRA_UID, uid)),
1468 "Update app-ops uidState in case package " + pkg + " changed");
Dianne Hackborn514074f2013-02-11 10:52:46 -08001469 }
1470 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001471 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07001472
Suprabh Shukla3017fe42018-11-08 19:00:01 -08001473 final IntentFilter packageSuspendFilter = new IntentFilter();
1474 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
1475 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1476 mContext.registerReceiver(new BroadcastReceiver() {
1477 @Override
1478 public void onReceive(Context context, Intent intent) {
1479 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1480 final String[] changedPkgs = intent.getStringArrayExtra(
1481 Intent.EXTRA_CHANGED_PACKAGE_LIST);
Suprabh Shuklab614a222019-09-12 14:42:46 -07001482 for (int code : OPS_RESTRICTED_ON_SUSPEND) {
1483 ArraySet<ModeCallback> callbacks;
1484 synchronized (AppOpsService.this) {
1485 callbacks = mOpModeWatchers.get(code);
1486 if (callbacks == null) {
1487 continue;
1488 }
1489 callbacks = new ArraySet<>(callbacks);
Dianne Hackborn65e8de32019-04-04 11:01:41 -07001490 }
Suprabh Shuklab614a222019-09-12 14:42:46 -07001491 for (int i = 0; i < changedUids.length; i++) {
1492 final int changedUid = changedUids[i];
1493 final String changedPkg = changedPkgs[i];
1494 // We trust packagemanager to insert matching uid and packageNames in the
1495 // extras
Suprabh Shukla7e017922019-08-05 17:13:23 -07001496 notifyOpChanged(callbacks, code, changedUid, changedPkg);
1497 }
Suprabh Shukla3017fe42018-11-08 19:00:01 -08001498 }
1499 }
1500 }, packageSuspendFilter);
1501
Suprabh Shuklaaef25132017-01-23 18:09:03 -08001502 PackageManagerInternal packageManagerInternal = LocalServices.getService(
1503 PackageManagerInternal.class);
1504 packageManagerInternal.setExternalSourcesPolicy(
1505 new PackageManagerInternal.ExternalSourcesPolicy() {
1506 @Override
1507 public int getPackageTrustedToInstallApps(String packageName, int uid) {
1508 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
1509 uid, packageName);
1510 switch (appOpMode) {
1511 case AppOpsManager.MODE_ALLOWED:
1512 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
1513 case AppOpsManager.MODE_ERRORED:
1514 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
1515 default:
1516 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
1517 }
1518 }
1519 });
1520
Jeff Sharkey10ec9d82018-11-28 14:52:45 -07001521 if (!StorageManager.hasIsolatedStorage()) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -07001522 StorageManagerInternal storageManagerInternal = LocalServices.getService(
1523 StorageManagerInternal.class);
1524 storageManagerInternal.addExternalStoragePolicy(
1525 new StorageManagerInternal.ExternalStorageMountPolicy() {
1526 @Override
1527 public int getMountMode(int uid, String packageName) {
1528 if (Process.isIsolated(uid)) {
1529 return Zygote.MOUNT_EXTERNAL_NONE;
1530 }
1531 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08001532 packageName, null, true, "External storage policy")
1533 != AppOpsManager.MODE_ALLOWED) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -07001534 return Zygote.MOUNT_EXTERNAL_NONE;
1535 }
1536 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08001537 packageName, null, true, "External storage policy")
1538 != AppOpsManager.MODE_ALLOWED) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -07001539 return Zygote.MOUNT_EXTERNAL_READ;
1540 }
1541 return Zygote.MOUNT_EXTERNAL_WRITE;
Svet Ganov6ee871e2015-07-10 14:29:33 -07001542 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07001543
Sudheer Shanka98cb3f02018-08-17 16:10:29 -07001544 @Override
1545 public boolean hasExternalStorage(int uid, String packageName) {
1546 final int mountMode = getMountMode(uid, packageName);
1547 return mountMode == Zygote.MOUNT_EXTERNAL_READ
1548 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
1549 }
1550 });
1551 }
Hui Yu88910de2019-12-16 14:35:27 -08001552 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001553 }
1554
1555 public void packageRemoved(int uid, String packageName) {
1556 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001557 UidState uidState = mUidStates.get(uid);
1558 if (uidState == null) {
1559 return;
1560 }
1561
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001562 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001563
1564 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001565 if (uidState.pkgOps != null) {
1566 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001567 }
1568
1569 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001570 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -07001571 && getPackagesForUid(uid).length <= 0) {
1572 mUidStates.remove(uid);
1573 }
1574
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001575 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001576 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001577
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001578 final int numOps = ops.size();
1579 for (int opNum = 0; opNum < numOps; opNum++) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001580 final Op op = ops.valueAt(opNum);
1581
1582 final int numFeatures = op.mFeatures.size();
1583 for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001584 FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
1585
1586 while (featureOp.mInProgressEvents != null) {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001587 featureOp.finished(featureOp.mInProgressEvents.keyAt(0));
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001588 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001589 }
1590 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001591 }
Winson470b15b2019-05-07 16:29:59 -07001592
1593 mHistoricalRegistry.clearHistory(uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001594 }
1595 }
1596
1597 public void uidRemoved(int uid) {
1598 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001599 if (mUidStates.indexOfKey(uid) >= 0) {
1600 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001601 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001602 }
1603 }
1604 }
1605
Hui Yu26969322019-08-21 14:56:35 -07001606 public void updateUidProcState(int uid, int procState,
1607 @ActivityManager.ProcessCapability int capability) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001608 synchronized (this) {
1609 final UidState uidState = getUidStateLocked(uid, true);
Hui Yu26969322019-08-21 14:56:35 -07001610 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
1611 if (uidState != null && (uidState.pendingState != newState
1612 || uidState.pendingCapability != capability)) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001613 final int oldPendingState = uidState.pendingState;
1614 uidState.pendingState = newState;
Hui Yu26969322019-08-21 14:56:35 -07001615 uidState.pendingCapability = capability;
Wei Wang878d0b62019-03-28 18:12:18 -07001616 if (newState < uidState.state
1617 || (newState <= UID_STATE_MAX_LAST_NON_RESTRICTED
1618 && uidState.state > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
1619 // We are moving to a more important state, or the new state may be in the
1620 // foreground and the old state is in the background, then always do it
1621 // immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001622 commitUidPendingStateLocked(uidState);
Hui Yu26969322019-08-21 14:56:35 -07001623 } else if (newState == uidState.state && capability != uidState.capability) {
1624 // No change on process state, but process capability has changed.
1625 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001626 } else if (uidState.pendingStateCommitTime == 0) {
1627 // We are moving to a less important state for the first time,
1628 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -07001629 final long settleTime;
1630 if (uidState.state <= UID_STATE_TOP) {
1631 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
1632 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
1633 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
1634 } else {
1635 settleTime = mConstants.BG_STATE_SETTLE_TIME;
1636 }
Dianne Hackborn9fb93502018-06-18 12:29:44 -07001637 uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001638 }
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001639
1640 if (uidState.pkgOps != null) {
1641 int numPkgs = uidState.pkgOps.size();
1642 for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
1643 Ops ops = uidState.pkgOps.valueAt(pkgNum);
1644
1645 int numOps = ops.size();
1646 for (int opNum = 0; opNum < numOps; opNum++) {
1647 Op op = ops.valueAt(opNum);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001648
1649 int numFeatures = op.mFeatures.size();
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001650 for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
1651 FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
1652
1653 featureOp.onUidStateChanged(newState);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001654 }
1655 }
1656 }
1657 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001658 }
1659 }
1660 }
1661
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001662 public void shutdown() {
1663 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -08001664 boolean doWrite = false;
1665 synchronized (this) {
1666 if (mWriteScheduled) {
1667 mWriteScheduled = false;
1668 doWrite = true;
1669 }
1670 }
1671 if (doWrite) {
1672 writeState();
1673 }
1674 }
1675
Dianne Hackborn72e39832013-01-18 18:36:09 -08001676 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
1677 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001678 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001679 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001680 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001681 for (int j=0; j<pkgOps.size(); j++) {
1682 Op curOp = pkgOps.valueAt(j);
Svet Ganovaf189e32019-02-15 18:45:29 -08001683 resOps.add(getOpEntryForResult(curOp, elapsedNow));
Dianne Hackborn72e39832013-01-18 18:36:09 -08001684 }
1685 } else {
1686 for (int j=0; j<ops.length; j++) {
1687 Op curOp = pkgOps.get(ops[j]);
1688 if (curOp != null) {
1689 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001690 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001691 }
Svet Ganovaf189e32019-02-15 18:45:29 -08001692 resOps.add(getOpEntryForResult(curOp, elapsedNow));
Dianne Hackborn72e39832013-01-18 18:36:09 -08001693 }
1694 }
1695 }
1696 return resOps;
1697 }
1698
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001699 @Nullable
1700 private ArrayList<AppOpsManager.OpEntry> collectUidOps(@NonNull UidState uidState,
1701 @Nullable int[] ops) {
1702 if (uidState.opModes == null) {
1703 return null;
1704 }
1705
1706 int opModeCount = uidState.opModes.size();
1707 if (opModeCount == 0) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08001708 return null;
1709 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001710 ArrayList<AppOpsManager.OpEntry> resOps = null;
1711 if (ops == null) {
1712 resOps = new ArrayList<>();
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001713 for (int i = 0; i < opModeCount; i++) {
1714 int code = uidState.opModes.keyAt(i);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001715 resOps.add(new OpEntry(code, uidState.opModes.get(code), Collections.emptyMap()));
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001716 }
1717 } else {
Hai Zhang93540ca2019-09-28 00:04:18 +00001718 for (int j=0; j<ops.length; j++) {
Philip P. Moltmannf56fe2c2019-10-30 08:42:47 -07001719 int code = ops[j];
1720 if (uidState.opModes.indexOfKey(code) >= 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001721 if (resOps == null) {
1722 resOps = new ArrayList<>();
1723 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001724 resOps.add(new OpEntry(code, uidState.opModes.get(code),
1725 Collections.emptyMap()));
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001726 }
1727 }
1728 }
1729 return resOps;
1730 }
1731
Svet Ganovaf189e32019-02-15 18:45:29 -08001732 private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, long elapsedNow) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001733 return op.createEntryLocked();
Svet Ganovaf189e32019-02-15 18:45:29 -08001734 }
1735
Dianne Hackborn35654b62013-01-14 17:38:02 -08001736 @Override
1737 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
1738 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1739 Binder.getCallingPid(), Binder.getCallingUid(), null);
1740 ArrayList<AppOpsManager.PackageOps> res = null;
1741 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001742 final int uidStateCount = mUidStates.size();
1743 for (int i = 0; i < uidStateCount; i++) {
1744 UidState uidState = mUidStates.valueAt(i);
1745 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
1746 continue;
1747 }
1748 ArrayMap<String, Ops> packages = uidState.pkgOps;
1749 final int packageCount = packages.size();
1750 for (int j = 0; j < packageCount; j++) {
1751 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001752 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001753 if (resOps != null) {
1754 if (res == null) {
1755 res = new ArrayList<AppOpsManager.PackageOps>();
1756 }
1757 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07001758 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001759 res.add(resPackage);
1760 }
1761 }
1762 }
1763 }
1764 return res;
1765 }
1766
1767 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -08001768 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
1769 int[] ops) {
1770 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1771 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00001772 String resolvedPackageName = resolvePackageName(uid, packageName);
1773 if (resolvedPackageName == null) {
1774 return Collections.emptyList();
1775 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08001776 synchronized (this) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001777 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false /* isPrivileged */,
Philip P. Moltmannec142a52019-04-09 13:38:07 -07001778 false /* edit */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001779 if (pkgOps == null) {
1780 return null;
1781 }
1782 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
1783 if (resOps == null) {
1784 return null;
1785 }
1786 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
1787 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07001788 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -08001789 res.add(resPackage);
1790 return res;
1791 }
1792 }
1793
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08001794 /**
1795 * Verify that historical appop request arguments are valid.
1796 */
1797 private void ensureHistoricalOpRequestIsValid(int uid, String packageName, String featureId,
1798 List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
1799 int flags) {
1800 if ((filter & FILTER_BY_UID) != 0) {
1801 Preconditions.checkArgument(uid != Process.INVALID_UID);
1802 } else {
1803 Preconditions.checkArgument(uid == Process.INVALID_UID);
1804 }
1805
1806 if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
1807 Objects.requireNonNull(packageName);
1808 } else {
1809 Preconditions.checkArgument(packageName == null);
1810 }
1811
1812 if ((filter & FILTER_BY_FEATURE_ID) == 0) {
1813 Preconditions.checkArgument(featureId == null);
1814 }
1815
1816 if ((filter & FILTER_BY_OP_NAMES) != 0) {
1817 Objects.requireNonNull(opNames);
1818 } else {
1819 Preconditions.checkArgument(opNames == null);
1820 }
1821
1822 Preconditions.checkFlagsArgument(filter,
1823 FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_FEATURE_ID | FILTER_BY_OP_NAMES);
1824 Preconditions.checkArgumentNonnegative(beginTimeMillis);
1825 Preconditions.checkArgument(endTimeMillis > beginTimeMillis);
1826 Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
1827 }
1828
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001829 @Override
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08001830 public void getHistoricalOps(int uid, String packageName, String featureId,
1831 List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
1832 int flags, RemoteCallback callback) {
1833 ensureHistoricalOpRequestIsValid(uid, packageName, featureId, opNames, filter,
1834 beginTimeMillis, endTimeMillis, flags);
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00001835 Objects.requireNonNull(callback, "callback cannot be null");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001836
Nate Myren697650b2020-01-23 13:25:06 -08001837 ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
1838 boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
1839 boolean isCallerStatsCollector = Binder.getCallingUid() == STATSD_UID;
1840
1841 if (!isCallerStatsCollector && !isCallerInstrumented) {
1842 mHandler.post(() -> callback.sendResult(new Bundle()));
1843 return;
1844 }
1845
Svet Ganovad0a49b2018-10-29 10:07:08 -07001846 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Svet Ganov8455ba22019-01-02 13:05:56 -08001847 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001848
Svet Ganov23c88db2019-01-22 20:38:11 -08001849 final String[] opNamesArray = (opNames != null)
1850 ? opNames.toArray(new String[opNames.size()]) : null;
Svet Ganovad0a49b2018-10-29 10:07:08 -07001851
Svet Ganovaf189e32019-02-15 18:45:29 -08001852 // Must not hold the appops lock
Svet Ganov73fd86e2020-01-09 20:26:14 -08001853 mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
1854 mHistoricalRegistry, uid, packageName, featureId, opNamesArray, filter,
1855 beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
Svet Ganovad0a49b2018-10-29 10:07:08 -07001856 }
1857
1858 @Override
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08001859 public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String featureId,
1860 List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
1861 int flags, RemoteCallback callback) {
1862 ensureHistoricalOpRequestIsValid(uid, packageName, featureId, opNames, filter,
1863 beginTimeMillis, endTimeMillis, flags);
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00001864 Objects.requireNonNull(callback, "callback cannot be null");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001865
Svet Ganov8e5bf962019-03-19 23:59:03 -07001866 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
Svet Ganov8455ba22019-01-02 13:05:56 -08001867 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
Svet Ganovad0a49b2018-10-29 10:07:08 -07001868
Svet Ganov23c88db2019-01-22 20:38:11 -08001869 final String[] opNamesArray = (opNames != null)
1870 ? opNames.toArray(new String[opNames.size()]) : null;
1871
Svet Ganov8455ba22019-01-02 13:05:56 -08001872 // Must not hold the appops lock
Svet Ganov73fd86e2020-01-09 20:26:14 -08001873 mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
1874 mHistoricalRegistry, uid, packageName, featureId, opNamesArray,
1875 filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
Svet Ganovad0a49b2018-10-29 10:07:08 -07001876 }
1877
1878 @Override
Svet Ganov8e5bf962019-03-19 23:59:03 -07001879 public void reloadNonHistoricalState() {
1880 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
1881 Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
1882 writeState();
1883 readState();
1884 }
1885
1886 @Override
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001887 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
1888 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
1889 Binder.getCallingPid(), Binder.getCallingUid(), null);
1890 synchronized (this) {
1891 UidState uidState = getUidStateLocked(uid, false);
1892 if (uidState == null) {
1893 return null;
1894 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001895 ArrayList<AppOpsManager.OpEntry> resOps = collectUidOps(uidState, ops);
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001896 if (resOps == null) {
1897 return null;
1898 }
Hai Zhang93540ca2019-09-28 00:04:18 +00001899 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001900 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
1901 null, uidState.uid, resOps);
1902 res.add(resPackage);
1903 return res;
1904 }
1905 }
1906
Eugene Susla463d5922019-07-17 18:14:15 -07001907 private void pruneOpLocked(Op op, int uid, String packageName) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001908 op.removeFeaturesWithNoTime();
1909
1910 if (op.mFeatures.size() == 0) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001911 Ops ops = getOpsRawLocked(uid, packageName, null, false /* isPrivileged */,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001912 false /* edit */);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001913 if (ops != null) {
1914 ops.remove(op.op);
1915 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07001916 UidState uidState = ops.uidState;
1917 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -07001918 if (pkgOps != null) {
1919 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001920 if (pkgOps.isEmpty()) {
1921 uidState.pkgOps = null;
1922 }
1923 if (uidState.isDefault()) {
1924 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07001925 }
1926 }
1927 }
1928 }
1929 }
1930 }
1931
Svet Ganovaf189e32019-02-15 18:45:29 -08001932 private void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07001933 if (callingPid == Process.myPid()) {
1934 return;
1935 }
1936 final int callingUser = UserHandle.getUserId(callingUid);
1937 synchronized (this) {
1938 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
1939 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
1940 // Profile owners are allowed to change modes but only for apps
1941 // within their user.
1942 return;
1943 }
1944 }
1945 }
1946 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
1947 Binder.getCallingPid(), Binder.getCallingUid(), null);
1948 }
1949
Dianne Hackborn72e39832013-01-18 18:36:09 -08001950 @Override
Svet Ganov2af57082015-07-30 08:44:20 -07001951 public void setUidMode(int code, int uid, int mode) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08001952 if (DEBUG) {
1953 Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
1954 + " by uid " + Binder.getCallingUid());
1955 }
1956
Dianne Hackbornd5254412018-05-11 18:02:58 -07001957 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -07001958 verifyIncomingOp(code);
1959 code = AppOpsManager.opToSwitch(code);
1960
Hai Zhange53e4c52019-10-08 18:57:01 -07001961 updatePermissionRevokedCompat(uid, code, mode);
1962
Svet Ganov2af57082015-07-30 08:44:20 -07001963 synchronized (this) {
1964 final int defaultMode = AppOpsManager.opToDefaultMode(code);
1965
1966 UidState uidState = getUidStateLocked(uid, false);
1967 if (uidState == null) {
1968 if (mode == defaultMode) {
1969 return;
1970 }
1971 uidState = new UidState(uid);
Hai Zhang93540ca2019-09-28 00:04:18 +00001972 uidState.opModes = new SparseIntArray();
1973 uidState.opModes.put(code, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07001974 mUidStates.put(uid, uidState);
1975 scheduleWriteLocked();
Hai Zhang93540ca2019-09-28 00:04:18 +00001976 } else if (uidState.opModes == null) {
1977 if (mode != defaultMode) {
1978 uidState.opModes = new SparseIntArray();
1979 uidState.opModes.put(code, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07001980 scheduleWriteLocked();
1981 }
Hai Zhang93540ca2019-09-28 00:04:18 +00001982 } else {
1983 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
1984 return;
1985 }
1986 if (mode == defaultMode) {
1987 uidState.opModes.delete(code);
1988 if (uidState.opModes.size() <= 0) {
1989 uidState.opModes = null;
1990 }
1991 } else {
1992 uidState.opModes.put(code, mode);
1993 }
1994 scheduleWriteLocked();
Svet Ganov2af57082015-07-30 08:44:20 -07001995 }
Wei Wang711eb662019-03-21 18:24:17 -07001996 uidState.evalForegroundOps(mOpModeWatchers);
Svet Ganov2af57082015-07-30 08:44:20 -07001997 }
1998
Svetoslav215b44a2015-08-04 19:03:40 -07001999 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002000 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07002001
riddle_hsu40b300f2015-11-23 13:22:03 +08002002 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002003 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07002004 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002005 final int callbackCount = callbacks.size();
2006 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002007 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08002008 ArraySet<String> changedPackages = new ArraySet<>();
2009 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002010 if (callbackSpecs == null) {
2011 callbackSpecs = new ArrayMap<>();
2012 }
riddle_hsu40b300f2015-11-23 13:22:03 +08002013 callbackSpecs.put(callback, changedPackages);
2014 }
2015 }
2016
2017 for (String uidPackageName : uidPackageNames) {
2018 callbacks = mPackageModeWatchers.get(uidPackageName);
2019 if (callbacks != null) {
2020 if (callbackSpecs == null) {
2021 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07002022 }
riddle_hsu40b300f2015-11-23 13:22:03 +08002023 final int callbackCount = callbacks.size();
2024 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002025 ModeCallback callback = callbacks.valueAt(i);
riddle_hsu40b300f2015-11-23 13:22:03 +08002026 ArraySet<String> changedPackages = callbackSpecs.get(callback);
2027 if (changedPackages == null) {
2028 changedPackages = new ArraySet<>();
2029 callbackSpecs.put(callback, changedPackages);
2030 }
2031 changedPackages.add(uidPackageName);
2032 }
Svet Ganov2af57082015-07-30 08:44:20 -07002033 }
2034 }
2035 }
2036
2037 if (callbackSpecs == null) {
Sudheer Shankab1613982019-05-16 16:55:50 -07002038 notifyOpChangedSync(code, uid, null, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07002039 return;
2040 }
2041
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002042 for (int i = 0; i < callbackSpecs.size(); i++) {
2043 final ModeCallback callback = callbackSpecs.keyAt(i);
2044 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
2045 if (reportedPackageNames == null) {
2046 mHandler.sendMessage(PooledLambda.obtainMessage(
2047 AppOpsService::notifyOpChanged,
2048 this, callback, code, uid, (String) null));
2049
2050 } else {
2051 final int reportedPackageCount = reportedPackageNames.size();
2052 for (int j = 0; j < reportedPackageCount; j++) {
2053 final String reportedPackageName = reportedPackageNames.valueAt(j);
2054 mHandler.sendMessage(PooledLambda.obtainMessage(
2055 AppOpsService::notifyOpChanged,
2056 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07002057 }
2058 }
Svet Ganov2af57082015-07-30 08:44:20 -07002059 }
Sudheer Shankab1613982019-05-16 16:55:50 -07002060
2061 notifyOpChangedSync(code, uid, null, mode);
2062 }
2063
Hai Zhange53e4c52019-10-08 18:57:01 -07002064 private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
Hai Zhang408ca762019-10-14 14:09:35 -07002065 PackageManagerInternal packageManagerInternal = LocalServices.getService(
2066 PackageManagerInternal.class);
2067 if (packageManagerInternal.getUidTargetSdkVersion(uid) >= Build.VERSION_CODES.M) {
2068 return;
2069 }
2070
Hai Zhange53e4c52019-10-08 18:57:01 -07002071 PackageManager packageManager = mContext.getPackageManager();
2072 String[] packageNames = packageManager.getPackagesForUid(uid);
2073 if (ArrayUtils.isEmpty(packageNames)) {
2074 return;
2075 }
2076 String packageName = packageNames[0];
2077
2078 List<Integer> ops = getSwitchOpToOps().get(switchCode);
2079 int opsSize = CollectionUtils.size(ops);
2080 for (int i = 0; i < opsSize; i++) {
2081 int code = ops.get(i);
2082
2083 String permissionName = AppOpsManager.opToPermission(code);
2084 if (permissionName == null) {
2085 continue;
2086 }
2087
2088 PermissionInfo permissionInfo;
2089 try {
2090 permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
2091 } catch (PackageManager.NameNotFoundException e) {
2092 e.printStackTrace();
2093 continue;
2094 }
2095
2096 if (!permissionInfo.isRuntime()) {
2097 continue;
2098 }
2099
2100 UserHandle user = UserHandle.getUserHandleForUid(uid);
2101 boolean isRevokedCompat;
2102 if (permissionInfo.backgroundPermission != null) {
2103 boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
2104 long identity = Binder.clearCallingIdentity();
2105 try {
2106 packageManager.updatePermissionFlags(permissionInfo.backgroundPermission,
2107 packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
2108 isBackgroundRevokedCompat
2109 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
2110 } finally {
2111 Binder.restoreCallingIdentity(identity);
2112 }
2113
2114 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED
2115 && mode != AppOpsManager.MODE_FOREGROUND;
2116 } else {
2117 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
2118 }
2119
2120 long identity = Binder.clearCallingIdentity();
2121 try {
2122 packageManager.updatePermissionFlags(permissionName, packageName,
2123 PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat
2124 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
2125 } finally {
2126 Binder.restoreCallingIdentity(identity);
2127 }
2128 }
2129 }
2130
2131 @NonNull
2132 private SparseArray<List<Integer>> getSwitchOpToOps() {
2133 synchronized (this) {
2134 if (mSwitchOpToOps == null) {
2135 mSwitchOpToOps = new SparseArray<>();
2136 for (int op = 0; op < _NUM_OP; op++) {
2137 int switchOp = AppOpsManager.opToSwitch(op);
2138 List<Integer> ops = mSwitchOpToOps.get(switchOp);
2139 if (ops == null) {
2140 ops = new ArrayList<>();
2141 mSwitchOpToOps.put(switchOp, ops);
2142 }
2143 ops.add(op);
2144 }
2145 }
2146 return mSwitchOpToOps;
2147 }
2148 }
2149
Sudheer Shankab1613982019-05-16 16:55:50 -07002150 private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) {
2151 final StorageManagerInternal storageManagerInternal =
2152 LocalServices.getService(StorageManagerInternal.class);
2153 if (storageManagerInternal != null) {
2154 storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode);
2155 }
Svet Ganov2af57082015-07-30 08:44:20 -07002156 }
2157
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002158 /**
2159 * Sets the mode for a certain op and uid.
2160 *
2161 * @param code The op code to set
2162 * @param uid The UID for which to set
2163 * @param packageName The package for which to set
2164 * @param mode The new mode to set
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002165 */
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002166 @Override
2167 public void setMode(int code, int uid, @NonNull String packageName, int mode) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002168 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002169 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002170 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08002171 code = AppOpsManager.opToSwitch(code);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002172
2173 boolean isPrivileged;
2174 try {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002175 isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002176 } catch (SecurityException e) {
2177 Slog.e(TAG, "Cannot setMode", e);
2178 return;
2179 }
2180
Hai Zhang2a31fd72019-12-10 15:48:22 -08002181 // STOPSHIP: Remove this check once we are sure no one is doing it.
2182 if (code == OP_COARSE_LOCATION && mode != AppOpsManager.opToDefaultMode(code)) {
2183 Slog.wtf(TAG, "Trying to setMode() instead of setUidMode(), " + "code=" + code
2184 + ", uid=" + uid + ", packageName=" + packageName + ", mode=" + mode
2185 + ", callingUid=" + Binder.getCallingUid(), new RuntimeException());
2186 }
2187
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002188 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07002189 UidState uidState = getUidStateLocked(uid, false);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002190 Op op = getOpLocked(code, uid, packageName, null, isPrivileged, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002191 if (op != null) {
2192 if (op.mode != mode) {
2193 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002194 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002195 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002196 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002197 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002198 if (cbs != null) {
2199 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002200 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002201 }
2202 repCbs.addAll(cbs);
2203 }
2204 cbs = mPackageModeWatchers.get(packageName);
2205 if (cbs != null) {
2206 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002207 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002208 }
2209 repCbs.addAll(cbs);
2210 }
David Braunf5d83192013-09-16 13:43:51 -07002211 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08002212 // If going into the default mode, prune this op
2213 // if there is nothing else interesting in it.
Eugene Susla463d5922019-07-17 18:14:15 -07002214 pruneOpLocked(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08002215 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002216 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002217 }
2218 }
2219 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08002220 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002221 mHandler.sendMessage(PooledLambda.obtainMessage(
2222 AppOpsService::notifyOpChanged,
2223 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08002224 }
Sudheer Shankab1613982019-05-16 16:55:50 -07002225
2226 notifyOpChangedSync(code, uid, packageName, mode);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002227 }
2228
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002229 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
2230 int uid, String packageName) {
2231 for (int i = 0; i < callbacks.size(); i++) {
2232 final ModeCallback callback = callbacks.valueAt(i);
2233 notifyOpChanged(callback, code, uid, packageName);
2234 }
2235 }
2236
2237 private void notifyOpChanged(ModeCallback callback, int code,
2238 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002239 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002240 return;
2241 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002242 // There are features watching for mode changes such as window manager
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002243 // and location manager which are in our process. The callbacks in these
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002244 // features may require permissions our remote caller does not have.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002245 final long identity = Binder.clearCallingIdentity();
2246 try {
2247 callback.mCallback.opChanged(code, uid, packageName);
2248 } catch (RemoteException e) {
2249 /* ignore */
2250 } finally {
2251 Binder.restoreCallingIdentity(identity);
2252 }
2253 }
2254
2255 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
2256 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
2257 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07002258 if (cbs == null) {
2259 return callbacks;
2260 }
2261 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002262 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002263 }
Svet Ganov2af57082015-07-30 08:44:20 -07002264 boolean duplicate = false;
Dianne Hackborn68d76552017-02-27 15:32:03 -08002265 final int N = cbs.size();
2266 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002267 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002268 ArrayList<ChangeRec> reports = callbacks.get(cb);
Dianne Hackborn607b4142013-08-02 18:10:10 -07002269 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002270 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002271 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07002272 } else {
2273 final int reportCount = reports.size();
2274 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002275 ChangeRec report = reports.get(j);
2276 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07002277 duplicate = true;
2278 break;
2279 }
2280 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002281 }
Svet Ganov2af57082015-07-30 08:44:20 -07002282 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002283 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07002284 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002285 }
2286 return callbacks;
2287 }
2288
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002289 static final class ChangeRec {
2290 final int op;
2291 final int uid;
2292 final String pkg;
2293
2294 ChangeRec(int _op, int _uid, String _pkg) {
2295 op = _op;
2296 uid = _uid;
2297 pkg = _pkg;
2298 }
2299 }
2300
Dianne Hackborn607b4142013-08-02 18:10:10 -07002301 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002302 public void resetAllModes(int reqUserId, String reqPackageName) {
2303 final int callingPid = Binder.getCallingPid();
2304 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002305 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
2306 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07002307
2308 int reqUid = -1;
2309 if (reqPackageName != null) {
2310 try {
2311 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07002312 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07002313 } catch (RemoteException e) {
2314 /* ignore - local call */
2315 }
2316 }
2317
Dianne Hackbornd5254412018-05-11 18:02:58 -07002318 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
2319
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002320 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07002321 synchronized (this) {
2322 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07002323 for (int i = mUidStates.size() - 1; i >= 0; i--) {
2324 UidState uidState = mUidStates.valueAt(i);
2325
Hai Zhang93540ca2019-09-28 00:04:18 +00002326 SparseIntArray opModes = uidState.opModes;
2327 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
2328 final int uidOpCount = opModes.size();
2329 for (int j = uidOpCount - 1; j >= 0; j--) {
2330 final int code = opModes.keyAt(j);
Svet Ganov2af57082015-07-30 08:44:20 -07002331 if (AppOpsManager.opAllowsReset(code)) {
Hai Zhang93540ca2019-09-28 00:04:18 +00002332 opModes.removeAt(j);
2333 if (opModes.size() <= 0) {
2334 uidState.opModes = null;
2335 }
Svet Ganov2af57082015-07-30 08:44:20 -07002336 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002337 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07002338 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002339 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07002340 mPackageModeWatchers.get(packageName));
2341 }
2342 }
2343 }
2344 }
2345
2346 if (uidState.pkgOps == null) {
2347 continue;
2348 }
2349
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002350 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07002351 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01002352 // Skip any ops for a different user
2353 continue;
2354 }
Svet Ganov2af57082015-07-30 08:44:20 -07002355
2356 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002357 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002358 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002359 while (it.hasNext()) {
2360 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002361 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002362 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
2363 // Skip any ops for a different package
2364 continue;
2365 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002366 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002367 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07002368 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07002369 if (AppOpsManager.opAllowsReset(curOp.op)
2370 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07002371 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07002372 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002373 uidChanged = true;
Svet Ganovaf189e32019-02-15 18:45:29 -08002374 final int uid = curOp.uidState.uid;
2375 callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07002376 mOpModeWatchers.get(curOp.op));
Svet Ganovaf189e32019-02-15 18:45:29 -08002377 callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07002378 mPackageModeWatchers.get(packageName));
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002379
2380 curOp.removeFeaturesWithNoTime();
2381 if (curOp.mFeatures.size() == 0) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002382 pkgOps.removeAt(j);
2383 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002384 }
2385 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002386 if (pkgOps.size() == 0) {
2387 it.remove();
2388 }
2389 }
Svet Ganov2af57082015-07-30 08:44:20 -07002390 if (uidState.isDefault()) {
2391 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07002392 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002393 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002394 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002395 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002396 }
Svet Ganov2af57082015-07-30 08:44:20 -07002397
Dianne Hackborn607b4142013-08-02 18:10:10 -07002398 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002399 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002400 }
2401 }
2402 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002403 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
2404 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002405 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002406 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002407 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002408 mHandler.sendMessage(PooledLambda.obtainMessage(
2409 AppOpsService::notifyOpChanged,
2410 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07002411 }
2412 }
2413 }
2414 }
2415
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002416 private void evalAllForegroundOpsLocked() {
2417 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
2418 final UidState uidState = mUidStates.valueAt(uidi);
2419 if (uidState.foregroundOps != null) {
2420 uidState.evalForegroundOps(mOpModeWatchers);
2421 }
2422 }
2423 }
2424
Dianne Hackbornc2293022013-02-06 23:14:49 -08002425 @Override
2426 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002427 startWatchingModeWithFlags(op, packageName, 0, callback);
2428 }
2429
2430 @Override
2431 public void startWatchingModeWithFlags(int op, String packageName, int flags,
2432 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002433 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002434 final int callingUid = Binder.getCallingUid();
2435 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07002436 // TODO: should have a privileged permission to protect this.
2437 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
2438 // the USAGE_STATS permission since this can provide information about when an
2439 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002440 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
2441 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08002442 if (callback == null) {
2443 return;
2444 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08002445 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07002446 op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002447 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08002448 if (cb == null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002449 cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002450 mModeWatchers.put(callback.asBinder(), cb);
2451 }
2452 if (op != AppOpsManager.OP_NONE) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002453 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002454 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08002455 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002456 mOpModeWatchers.put(op, cbs);
2457 }
2458 cbs.add(cb);
2459 }
2460 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002461 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002462 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08002463 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002464 mPackageModeWatchers.put(packageName, cbs);
2465 }
2466 cbs.add(cb);
2467 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002468 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002469 }
2470 }
2471
2472 @Override
2473 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08002474 if (callback == null) {
2475 return;
2476 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08002477 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002478 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08002479 if (cb != null) {
2480 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002481 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002482 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002483 cbs.remove(cb);
2484 if (cbs.size() <= 0) {
2485 mOpModeWatchers.removeAt(i);
2486 }
2487 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002488 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002489 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002490 cbs.remove(cb);
2491 if (cbs.size() <= 0) {
2492 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002493 }
2494 }
2495 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002496 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002497 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002498 }
2499
Svet Ganovd873ae62018-06-25 16:39:23 -07002500 public CheckOpsDelegate getAppOpsServiceDelegate() {
2501 synchronized (this) {
2502 return mCheckOpsDelegate;
2503 }
2504 }
2505
2506 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
2507 synchronized (this) {
2508 mCheckOpsDelegate = delegate;
2509 }
2510 }
2511
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002512 @Override
Svet Ganov9d528a12018-12-19 17:23:11 -08002513 public int checkOperationRaw(int code, int uid, String packageName) {
2514 return checkOperationInternal(code, uid, packageName, true /*raw*/);
2515 }
2516
2517 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08002518 public int checkOperation(int code, int uid, String packageName) {
Svet Ganov9d528a12018-12-19 17:23:11 -08002519 return checkOperationInternal(code, uid, packageName, false /*raw*/);
2520 }
2521
2522 private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002523 final CheckOpsDelegate delegate;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002524 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002525 delegate = mCheckOpsDelegate;
2526 }
Todd Kennedy556efba2018-11-15 07:43:55 -08002527 if (delegate == null) {
Svet Ganov9d528a12018-12-19 17:23:11 -08002528 return checkOperationImpl(code, uid, packageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08002529 }
Svet Ganov9d528a12018-12-19 17:23:11 -08002530 return delegate.checkOperation(code, uid, packageName, raw,
Svet Ganovd873ae62018-06-25 16:39:23 -07002531 AppOpsService.this::checkOperationImpl);
2532 }
2533
Svet Ganov9d528a12018-12-19 17:23:11 -08002534 private int checkOperationImpl(int code, int uid, String packageName,
2535 boolean raw) {
Todd Kennedy556efba2018-11-15 07:43:55 -08002536 verifyIncomingUid(uid);
2537 verifyIncomingOp(code);
2538 String resolvedPackageName = resolvePackageName(uid, packageName);
2539 if (resolvedPackageName == null) {
2540 return AppOpsManager.MODE_IGNORED;
2541 }
Svet Ganov9d528a12018-12-19 17:23:11 -08002542 return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08002543 }
2544
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002545 /**
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002546 * Get the mode of an app-op.
2547 *
2548 * @param code The code of the op
2549 * @param uid The uid of the package the op belongs to
2550 * @param packageName The package the op belongs to
2551 * @param raw If the raw state of eval-ed state should be checked.
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002552 *
2553 * @return The mode of the op
2554 */
2555 private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
Philip P. Moltmannd4ab19e2019-05-07 08:57:35 -07002556 boolean raw) {
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07002557 boolean isPrivileged;
2558
2559 try {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002560 isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07002561 } catch (SecurityException e) {
2562 Slog.e(TAG, "checkOperation", e);
2563 return AppOpsManager.opToDefaultMode(code);
2564 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002565
Suprabh Shukla7e017922019-08-05 17:13:23 -07002566 if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
2567 return AppOpsManager.MODE_IGNORED;
2568 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002569 synchronized (this) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002570 if (isOpRestrictedLocked(uid, code, packageName, null, isPrivileged)) {
Jason Monk62062992014-05-06 09:55:28 -04002571 return AppOpsManager.MODE_IGNORED;
2572 }
Svet Ganov2af57082015-07-30 08:44:20 -07002573 code = AppOpsManager.opToSwitch(code);
2574 UidState uidState = getUidStateLocked(uid, false);
Hai Zhang93540ca2019-09-28 00:04:18 +00002575 if (uidState != null && uidState.opModes != null
2576 && uidState.opModes.indexOfKey(code) >= 0) {
2577 final int rawMode = uidState.opModes.get(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08002578 return raw ? rawMode : uidState.evalMode(code, rawMode);
Svet Ganov2af57082015-07-30 08:44:20 -07002579 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002580 Op op = getOpLocked(code, uid, packageName, null, false, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002581 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07002582 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002583 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002584 return raw ? op.mode : op.evalMode();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002585 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002586 }
2587
2588 @Override
John Spurlock7b414672014-07-18 13:02:39 -04002589 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002590 final CheckOpsDelegate delegate;
John Spurlock1af30c72014-03-10 08:33:35 -04002591 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002592 delegate = mCheckOpsDelegate;
2593 }
Todd Kennedy556efba2018-11-15 07:43:55 -08002594 if (delegate == null) {
2595 return checkAudioOperationImpl(code, usage, uid, packageName);
2596 }
Svet Ganovd873ae62018-06-25 16:39:23 -07002597 return delegate.checkAudioOperation(code, usage, uid, packageName,
2598 AppOpsService.this::checkAudioOperationImpl);
2599 }
2600
2601 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002602 final int mode = mAudioRestrictionManager.checkAudioOperation(
2603 code, usage, uid, packageName);
2604 if (mode != AppOpsManager.MODE_ALLOWED) {
2605 return mode;
John Spurlock1af30c72014-03-10 08:33:35 -04002606 }
2607 return checkOperation(code, uid, packageName);
2608 }
2609
John Spurlock1af30c72014-03-10 08:33:35 -04002610 @Override
John Spurlock7b414672014-07-18 13:02:39 -04002611 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04002612 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002613 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04002614 verifyIncomingUid(uid);
2615 verifyIncomingOp(code);
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002616
2617 mAudioRestrictionManager.setZenModeAudioRestriction(
2618 code, usage, uid, mode, exceptionPackages);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002619
2620 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07002621 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04002622 }
2623
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002624
2625 @Override
2626 public void setCameraAudioRestriction(@CAMERA_AUDIO_RESTRICTION int mode) {
2627 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), -1);
2628
2629 mAudioRestrictionManager.setCameraAudioRestriction(mode);
2630
2631 mHandler.sendMessage(PooledLambda.obtainMessage(
2632 AppOpsService::notifyWatchersOfChange, this,
2633 AppOpsManager.OP_PLAY_AUDIO, UID_ANY));
2634 mHandler.sendMessage(PooledLambda.obtainMessage(
2635 AppOpsService::notifyWatchersOfChange, this,
2636 AppOpsManager.OP_VIBRATE, UID_ANY));
2637 }
2638
John Spurlock1af30c72014-03-10 08:33:35 -04002639 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002640 public int checkPackage(int uid, String packageName) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002641 Objects.requireNonNull(packageName);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002642 try {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002643 verifyAndGetIsPrivileged(uid, packageName, null);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002644
2645 return AppOpsManager.MODE_ALLOWED;
2646 } catch (SecurityException ignored) {
2647 return AppOpsManager.MODE_ERRORED;
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002648 }
2649 }
2650
2651 @Override
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002652 public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
2653 String proxiedFeatureId, int proxyUid, String proxyPackageName,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002654 String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002655 verifyIncomingUid(proxyUid);
Svet Ganov99b60432015-06-27 13:15:22 -07002656 verifyIncomingOp(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08002657
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002658 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
2659 if (resolveProxyPackageName == null) {
2660 return AppOpsManager.MODE_IGNORED;
2661 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002662
2663 final boolean isProxyTrusted = mContext.checkPermission(
2664 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
2665 == PackageManager.PERMISSION_GRANTED;
2666
2667 final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
2668 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002669 final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002670 proxyFeatureId, Process.INVALID_UID, null, null, proxyFlags,
2671 !isProxyTrusted, "proxy " + message);
Svet Ganov99b60432015-06-27 13:15:22 -07002672 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
2673 return proxyMode;
2674 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002675
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002676 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
2677 if (resolveProxiedPackageName == null) {
2678 return AppOpsManager.MODE_IGNORED;
2679 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002680 final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
2681 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002682 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002683 proxiedFeatureId, proxyUid, resolveProxyPackageName, proxyFeatureId,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002684 proxiedFlags, shouldCollectAsyncNotedOp, message);
Svet Ganov99b60432015-06-27 13:15:22 -07002685 }
2686
2687 @Override
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002688 public int noteOperation(int code, int uid, String packageName, String featureId,
2689 boolean shouldCollectAsyncNotedOp, String message) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002690 final CheckOpsDelegate delegate;
2691 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002692 delegate = mCheckOpsDelegate;
2693 }
Todd Kennedy556efba2018-11-15 07:43:55 -08002694 if (delegate == null) {
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002695 return noteOperationImpl(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
2696 message);
Todd Kennedy556efba2018-11-15 07:43:55 -08002697 }
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002698 return delegate.noteOperation(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
2699 message, AppOpsService.this::noteOperationImpl);
Svet Ganovd873ae62018-06-25 16:39:23 -07002700 }
2701
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002702 private int noteOperationImpl(int code, int uid, @Nullable String packageName,
2703 @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
2704 @Nullable String message) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002705 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002706 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002707 String resolvedPackageName = resolvePackageName(uid, packageName);
2708 if (resolvedPackageName == null) {
2709 return AppOpsManager.MODE_IGNORED;
2710 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002711 return noteOperationUnchecked(code, uid, resolvedPackageName, featureId,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002712 Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF,
2713 shouldCollectAsyncNotedOp, message);
Svet Ganov99b60432015-06-27 13:15:22 -07002714 }
2715
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002716 private int noteOperationUnchecked(int code, int uid, @NonNull String packageName,
2717 @Nullable String featureId, int proxyUid, String proxyPackageName,
2718 @Nullable String proxyFeatureId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp,
2719 @Nullable String message) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002720 boolean isPrivileged;
2721 try {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002722 isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002723 } catch (SecurityException e) {
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07002724 Slog.e(TAG, "noteOperation", e);
2725 return AppOpsManager.MODE_ERRORED;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002726 }
2727
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002728 synchronized (this) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002729 final Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
2730 true /* edit */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002731 if (ops == null) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002732 scheduleOpNotedIfNeededLocked(code, uid, packageName,
2733 AppOpsManager.MODE_IGNORED);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002734 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002735 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002736 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002737 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002738 final Op op = getOpLocked(ops, code, uid, true);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002739 final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002740 if (isOpRestrictedLocked(uid, code, packageName, featureId, isPrivileged)) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002741 scheduleOpNotedIfNeededLocked(code, uid, packageName,
2742 AppOpsManager.MODE_IGNORED);
Jason Monk62062992014-05-06 09:55:28 -04002743 return AppOpsManager.MODE_IGNORED;
2744 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07002745 final UidState uidState = ops.uidState;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08002746 if (featureOp.isRunning()) {
2747 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
2748 + code + " startTime of in progress event="
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08002749 + featureOp.mInProgressEvents.valueAt(0).getStartTime());
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002750 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002751
Dianne Hackbornf265ea92013-01-31 15:00:51 -08002752 final int switchCode = AppOpsManager.opToSwitch(code);
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07002753 // If there is a non-default per UID policy (we set UID op mode only if
2754 // non-default) it takes over, otherwise use the per package policy.
Hai Zhang93540ca2019-09-28 00:04:18 +00002755 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
2756 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07002757 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002758 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07002759 + switchCode + " (" + code + ") uid " + uid + " package "
2760 + packageName);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08002761 featureOp.rejected(uidState.state, flags);
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002762 scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
Svet Ganov2af57082015-07-30 08:44:20 -07002763 return uidMode;
2764 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07002765 } else {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002766 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
2767 : op;
Svet Ganovaf189e32019-02-15 18:45:29 -08002768 final int mode = switchOp.evalMode();
Philip P. Moltmann721c9682019-12-20 11:41:46 -08002769 if (mode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002770 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07002771 + switchCode + " (" + code + ") uid " + uid + " package "
2772 + packageName);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08002773 featureOp.rejected(uidState.state, flags);
Svet Ganovaf189e32019-02-15 18:45:29 -08002774 scheduleOpNotedIfNeededLocked(code, uid, packageName, mode);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002775 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07002776 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002777 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002778 if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002779 + " package " + packageName + (featureId == null ? "" : "." + featureId));
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08002780 featureOp.accessed(proxyUid, proxyPackageName, proxyFeatureId, uidState.state, flags);
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002781 scheduleOpNotedIfNeededLocked(code, uid, packageName,
2782 AppOpsManager.MODE_ALLOWED);
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002783
2784 if (shouldCollectAsyncNotedOp) {
2785 collectAsyncNotedOp(uid, packageName, code, featureId, message);
2786 }
2787
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002788 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002789 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002790 }
2791
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002792 // TODO moltmann: Allow watching for feature ops
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002793 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002794 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Svet Ganovf7b47252018-02-26 11:11:27 -08002795 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002796 final int callingUid = Binder.getCallingUid();
2797 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08002798 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2799 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002800 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08002801 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002802 if (ops != null) {
2803 Preconditions.checkArrayElementsInRange(ops, 0,
2804 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
2805 }
2806 if (callback == null) {
2807 return;
2808 }
2809 synchronized (this) {
2810 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
2811 if (callbacks == null) {
2812 callbacks = new SparseArray<>();
2813 mActiveWatchers.put(callback.asBinder(), callbacks);
2814 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002815 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
2816 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002817 for (int op : ops) {
2818 callbacks.put(op, activeCallback);
2819 }
2820 }
2821 }
2822
2823 @Override
2824 public void stopWatchingActive(IAppOpsActiveCallback callback) {
2825 if (callback == null) {
2826 return;
2827 }
2828 synchronized (this) {
2829 final SparseArray<ActiveCallback> activeCallbacks =
2830 mActiveWatchers.remove(callback.asBinder());
2831 if (activeCallbacks == null) {
2832 return;
2833 }
2834 final int callbackCount = activeCallbacks.size();
2835 for (int i = 0; i < callbackCount; i++) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002836 activeCallbacks.valueAt(i).destroy();
2837 }
2838 }
2839 }
2840
2841 @Override
2842 public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
2843 int watchedUid = Process.INVALID_UID;
2844 final int callingUid = Binder.getCallingUid();
2845 final int callingPid = Binder.getCallingPid();
2846 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
2847 != PackageManager.PERMISSION_GRANTED) {
2848 watchedUid = callingUid;
2849 }
2850 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
2851 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
2852 "Invalid op code in: " + Arrays.toString(ops));
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002853 Objects.requireNonNull(callback, "Callback cannot be null");
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002854 synchronized (this) {
2855 SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
2856 if (callbacks == null) {
2857 callbacks = new SparseArray<>();
2858 mNotedWatchers.put(callback.asBinder(), callbacks);
2859 }
2860 final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
2861 callingUid, callingPid);
2862 for (int op : ops) {
2863 callbacks.put(op, notedCallback);
2864 }
2865 }
2866 }
2867
2868 @Override
2869 public void stopWatchingNoted(IAppOpsNotedCallback callback) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002870 Objects.requireNonNull(callback, "Callback cannot be null");
Svet Ganovb3d2ae22018-12-17 22:06:15 -08002871 synchronized (this) {
2872 final SparseArray<NotedCallback> notedCallbacks =
2873 mNotedWatchers.remove(callback.asBinder());
2874 if (notedCallbacks == null) {
2875 return;
2876 }
2877 final int callbackCount = notedCallbacks.size();
2878 for (int i = 0; i < callbackCount; i++) {
2879 notedCallbacks.valueAt(i).destroy();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002880 }
2881 }
2882 }
2883
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002884 /**
2885 * Collect an {@link AsyncNotedAppOp}.
2886 *
2887 * @param uid The uid the op was noted for
2888 * @param packageName The package the op was noted for
2889 * @param opCode The code of the op noted
2890 * @param featureId The id of the feature to op was noted for
2891 * @param message The message for the op noting
2892 */
2893 private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
2894 @Nullable String featureId, @NonNull String message) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002895 Objects.requireNonNull(message);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002896
2897 int callingUid = Binder.getCallingUid();
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002898
2899 long token = Binder.clearCallingIdentity();
2900 try {
2901 synchronized (this) {
2902 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2903
2904 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2905 AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08002906 featureId, message, System.currentTimeMillis());
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002907 final boolean[] wasNoteForwarded = {false};
2908
2909 if (callbacks != null) {
2910 callbacks.broadcast((cb) -> {
2911 try {
2912 cb.opNoted(asyncNotedOp);
2913 wasNoteForwarded[0] = true;
2914 } catch (RemoteException e) {
2915 Slog.e(TAG,
2916 "Could not forward noteOp of " + opCode + " to " + packageName
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002917 + "/" + uid + "(" + featureId + ")", e);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002918 }
2919 });
2920 }
2921
2922 if (!wasNoteForwarded[0]) {
2923 ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
2924 if (unforwardedOps == null) {
2925 unforwardedOps = new ArrayList<>(1);
2926 mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
2927 }
2928
2929 unforwardedOps.add(asyncNotedOp);
2930 if (unforwardedOps.size() > MAX_UNFORWARED_OPS) {
2931 unforwardedOps.remove(0);
2932 }
2933 }
2934 }
2935 } finally {
2936 Binder.restoreCallingIdentity(token);
2937 }
2938 }
2939
2940 /**
2941 * Compute a key to be used in {@link #mAsyncOpWatchers} and {@link #mUnforwardedAsyncNotedOps}
2942 *
2943 * @param packageName The package name of the app
2944 * @param uid The uid of the app
2945 *
2946 * @return They key uniquely identifying the app
2947 */
2948 private @NonNull Pair<String, Integer> getAsyncNotedOpsKey(@NonNull String packageName,
2949 int uid) {
2950 return new Pair<>(packageName, uid);
2951 }
2952
2953 @Override
2954 public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002955 Objects.requireNonNull(packageName);
2956 Objects.requireNonNull(callback);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002957
2958 int uid = Binder.getCallingUid();
2959 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2960
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002961 verifyAndGetIsPrivileged(uid, packageName, null);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002962
2963 synchronized (this) {
2964 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2965 if (callbacks == null) {
2966 callbacks = new RemoteCallbackList<IAppOpsAsyncNotedCallback>() {
2967 @Override
2968 public void onCallbackDied(IAppOpsAsyncNotedCallback callback) {
2969 synchronized (AppOpsService.this) {
2970 if (getRegisteredCallbackCount() == 0) {
2971 mAsyncOpWatchers.remove(key);
2972 }
2973 }
2974 }
2975 };
2976 mAsyncOpWatchers.put(key, callbacks);
2977 }
2978
2979 callbacks.register(callback);
2980 }
2981 }
2982
2983 @Override
2984 public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002985 Objects.requireNonNull(packageName);
2986 Objects.requireNonNull(callback);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002987
2988 int uid = Binder.getCallingUid();
2989 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
2990
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002991 verifyAndGetIsPrivileged(uid, packageName, null);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07002992
2993 synchronized (this) {
2994 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
2995 if (callbacks != null) {
2996 callbacks.unregister(callback);
2997 if (callbacks.getRegisteredCallbackCount() == 0) {
2998 mAsyncOpWatchers.remove(key);
2999 }
3000 }
3001 }
3002 }
3003
3004 @Override
3005 public List<AsyncNotedAppOp> extractAsyncOps(String packageName) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00003006 Objects.requireNonNull(packageName);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003007
3008 int uid = Binder.getCallingUid();
3009
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003010 verifyAndGetIsPrivileged(uid, packageName, null);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003011
3012 synchronized (this) {
3013 return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
3014 }
3015 }
3016
3017 @Override
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003018 public int startOperation(IBinder clientId, int code, int uid, String packageName,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003019 String featureId, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
3020 String message) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003021 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08003022 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003023 String resolvedPackageName = resolvePackageName(uid, packageName);
3024 if (resolvedPackageName == null) {
3025 return AppOpsManager.MODE_IGNORED;
3026 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003027
3028 boolean isPrivileged;
3029 try {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003030 isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003031 } catch (SecurityException e) {
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07003032 Slog.e(TAG, "startOperation", e);
3033 return AppOpsManager.MODE_ERRORED;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003034 }
3035
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003036 synchronized (this) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003037 final Ops ops = getOpsRawLocked(uid, resolvedPackageName, featureId, isPrivileged,
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003038 true /* edit */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003039 if (ops == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003040 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003041 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07003042 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003043 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003044 final Op op = getOpLocked(ops, code, uid, true);
3045 if (isOpRestrictedLocked(uid, code, resolvedPackageName, featureId, isPrivileged)) {
Jason Monk62062992014-05-06 09:55:28 -04003046 return AppOpsManager.MODE_IGNORED;
3047 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003048 final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003049 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003050 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003051 // If there is a non-default per UID policy (we set UID op mode only if
3052 // non-default) it takes over, otherwise use the per package policy.
Svet Ganovaf189e32019-02-15 18:45:29 -08003053 final int opCode = op.op;
Hai Zhang93540ca2019-09-28 00:04:18 +00003054 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
3055 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08003056 if (uidMode != AppOpsManager.MODE_ALLOWED
3057 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003058 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07003059 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003060 + resolvedPackageName);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003061 featureOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
Svet Ganov2af57082015-07-30 08:44:20 -07003062 return uidMode;
3063 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003064 } else {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003065 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
3066 : op;
Svet Ganovaf189e32019-02-15 18:45:29 -08003067 final int mode = switchOp.evalMode();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003068 if (mode != AppOpsManager.MODE_ALLOWED
3069 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
3070 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003071 + switchCode + " (" + code + ") uid " + uid + " package "
3072 + resolvedPackageName);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003073 featureOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003074 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003075 }
Svet Ganov2af57082015-07-30 08:44:20 -07003076 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003077 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003078 + " package " + resolvedPackageName);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003079 try {
3080 featureOp.started(clientId, uidState.state);
3081 } catch (RemoteException e) {
3082 throw new RuntimeException(e);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003083 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003084 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003085
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003086 if (shouldCollectAsyncNotedOp) {
3087 collectAsyncNotedOp(uid, packageName, code, featureId, message);
3088 }
3089
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003090 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003091 }
3092
3093 @Override
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003094 public void finishOperation(IBinder clientId, int code, int uid, String packageName,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003095 String featureId) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003096 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08003097 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003098 String resolvedPackageName = resolvePackageName(uid, packageName);
3099 if (resolvedPackageName == null) {
3100 return;
3101 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003102
3103 boolean isPrivileged;
3104 try {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003105 isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003106 } catch (SecurityException e) {
3107 Slog.e(TAG, "Cannot finishOperation", e);
3108 return;
3109 }
3110
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003111 synchronized (this) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003112 Op op = getOpLocked(code, uid, resolvedPackageName, featureId, isPrivileged, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003113 if (op == null) {
3114 return;
3115 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003116 final FeatureOp featureOp = op.mFeatures.get(featureId);
3117 if (featureOp == null) {
3118 return;
3119 }
3120
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003121 try {
3122 featureOp.finished(clientId);
3123 } catch (IllegalStateException e) {
3124 Slog.e(TAG, "Operation not started: uid=" + uid + " pkg="
3125 + packageName + " op=" + AppOpsManager.opToName(code), e);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003126 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003127 }
3128 }
3129
3130 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
3131 boolean active) {
3132 ArraySet<ActiveCallback> dispatchedCallbacks = null;
3133 final int callbackListCount = mActiveWatchers.size();
3134 for (int i = 0; i < callbackListCount; i++) {
3135 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
3136 ActiveCallback callback = callbacks.get(code);
3137 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003138 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003139 continue;
3140 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003141 if (dispatchedCallbacks == null) {
3142 dispatchedCallbacks = new ArraySet<>();
3143 }
3144 dispatchedCallbacks.add(callback);
3145 }
3146 }
3147 if (dispatchedCallbacks == null) {
3148 return;
3149 }
3150 mHandler.sendMessage(PooledLambda.obtainMessage(
3151 AppOpsService::notifyOpActiveChanged,
3152 this, dispatchedCallbacks, code, uid, packageName, active));
3153 }
3154
3155 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
3156 int code, int uid, String packageName, boolean active) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003157 // There are features watching for mode changes such as window manager
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003158 // and location manager which are in our process. The callbacks in these
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003159 // features may require permissions our remote caller does not have.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003160 final long identity = Binder.clearCallingIdentity();
3161 try {
3162 final int callbackCount = callbacks.size();
3163 for (int i = 0; i < callbackCount; i++) {
3164 final ActiveCallback callback = callbacks.valueAt(i);
3165 try {
3166 callback.mCallback.opActiveChanged(code, uid, packageName, active);
3167 } catch (RemoteException e) {
3168 /* do nothing */
3169 }
3170 }
3171 } finally {
3172 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003173 }
3174 }
3175
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003176 private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
3177 int result) {
3178 ArraySet<NotedCallback> dispatchedCallbacks = null;
3179 final int callbackListCount = mNotedWatchers.size();
3180 for (int i = 0; i < callbackListCount; i++) {
3181 final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
3182 final NotedCallback callback = callbacks.get(code);
3183 if (callback != null) {
3184 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
3185 continue;
3186 }
3187 if (dispatchedCallbacks == null) {
3188 dispatchedCallbacks = new ArraySet<>();
3189 }
3190 dispatchedCallbacks.add(callback);
3191 }
3192 }
3193 if (dispatchedCallbacks == null) {
3194 return;
3195 }
3196 mHandler.sendMessage(PooledLambda.obtainMessage(
3197 AppOpsService::notifyOpChecked,
3198 this, dispatchedCallbacks, code, uid, packageName, result));
3199 }
3200
3201 private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
3202 int code, int uid, String packageName, int result) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003203 // There are features watching for checks in our process. The callbacks in
3204 // these features may require permissions our remote caller does not have.
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003205 final long identity = Binder.clearCallingIdentity();
3206 try {
3207 final int callbackCount = callbacks.size();
3208 for (int i = 0; i < callbackCount; i++) {
3209 final NotedCallback callback = callbacks.valueAt(i);
3210 try {
3211 callback.mCallback.opNoted(code, uid, packageName, result);
3212 } catch (RemoteException e) {
3213 /* do nothing */
3214 }
3215 }
3216 } finally {
3217 Binder.restoreCallingIdentity(identity);
3218 }
3219 }
3220
Svet Ganovb9d71a62015-04-30 10:38:13 -07003221 @Override
3222 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003223 if (permission == null) {
3224 return AppOpsManager.OP_NONE;
3225 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07003226 return AppOpsManager.permissionToOpCode(permission);
3227 }
3228
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003229 @Override
3230 public boolean shouldCollectNotes(int opCode) {
3231 Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
3232
3233 String perm = AppOpsManager.opToPermission(opCode);
3234 if (perm == null) {
3235 return false;
3236 }
3237
3238 PermissionInfo permInfo;
3239 try {
3240 permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
3241 } catch (PackageManager.NameNotFoundException e) {
3242 return false;
3243 }
3244
3245 return permInfo.getProtection() == PROTECTION_DANGEROUS;
3246 }
3247
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003248 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003249 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003250 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003251 }
3252 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003253 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003254 }
3255 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
3256 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003257 }
3258
Dianne Hackborn961321f2013-02-05 17:22:41 -08003259 private void verifyIncomingOp(int op) {
3260 if (op >= 0 && op < AppOpsManager._NUM_OP) {
3261 return;
3262 }
3263 throw new IllegalArgumentException("Bad operation #" + op);
3264 }
3265
Philip P. Moltmann724150d2019-03-11 17:01:05 -07003266 private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07003267 UidState uidState = mUidStates.get(uid);
3268 if (uidState == null) {
3269 if (!edit) {
3270 return null;
3271 }
3272 uidState = new UidState(uid);
3273 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003274 } else {
3275 if (uidState.pendingStateCommitTime != 0) {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003276 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003277 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003278 } else {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003279 mLastRealtime = SystemClock.elapsedRealtime();
3280 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003281 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003282 }
3283 }
3284 }
Svet Ganov2af57082015-07-30 08:44:20 -07003285 }
3286 return uidState;
3287 }
3288
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003289 private void commitUidPendingStateLocked(UidState uidState) {
Wei Wang878d0b62019-03-28 18:12:18 -07003290 if (uidState.hasForegroundWatchers) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003291 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
3292 if (!uidState.foregroundOps.valueAt(fgi)) {
3293 continue;
3294 }
3295 final int code = uidState.foregroundOps.keyAt(fgi);
Svet Ganovaf189e32019-02-15 18:45:29 -08003296 // For location ops we consider fg state only if the fg service
3297 // is of location type, for all other ops any fg service will do.
Wei Wang711eb662019-03-21 18:24:17 -07003298 final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code);
3299 final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState;
3300 final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState;
Hui Yu88910de2019-12-16 14:35:27 -08003301 if (resolvedLastFg == resolvedNowFg
3302 && uidState.capability == uidState.pendingCapability
3303 && uidState.appWidgetVisible == uidState.pendingAppWidgetVisible) {
Svet Ganovaf189e32019-02-15 18:45:29 -08003304 continue;
3305 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003306 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
3307 if (callbacks != null) {
3308 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
3309 final ModeCallback callback = callbacks.valueAt(cbi);
3310 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
3311 || !callback.isWatchingUid(uidState.uid)) {
3312 continue;
3313 }
Hai Zhang93540ca2019-09-28 00:04:18 +00003314 boolean doAllPackages = uidState.opModes != null
3315 && uidState.opModes.indexOfKey(code) >= 0
3316 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003317 if (uidState.pkgOps != null) {
3318 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
3319 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08003320 if (op == null) {
3321 continue;
3322 }
3323 if (doAllPackages || op.mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003324 mHandler.sendMessage(PooledLambda.obtainMessage(
3325 AppOpsService::notifyOpChanged,
3326 this, callback, code, uidState.uid,
3327 uidState.pkgOps.keyAt(pkgi)));
3328 }
3329 }
3330 }
3331 }
3332 }
3333 }
3334 }
Wei Wang711eb662019-03-21 18:24:17 -07003335 uidState.state = uidState.pendingState;
Hui Yu26969322019-08-21 14:56:35 -07003336 uidState.capability = uidState.pendingCapability;
Hui Yu88910de2019-12-16 14:35:27 -08003337 uidState.appWidgetVisible = uidState.pendingAppWidgetVisible;
Wei Wang711eb662019-03-21 18:24:17 -07003338 uidState.pendingStateCommitTime = 0;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003339 }
3340
Hui Yu88910de2019-12-16 14:35:27 -08003341 private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
3342 synchronized (this) {
3343 for (int i = uidPackageNames.size() - 1; i >= 0; i--) {
3344 final int uid = uidPackageNames.keyAt(i);
3345 final UidState uidState = getUidStateLocked(uid, true);
3346 if (uidState != null && (uidState.pendingAppWidgetVisible != visible)) {
3347 uidState.pendingAppWidgetVisible = visible;
3348 if (uidState.pendingAppWidgetVisible != uidState.appWidgetVisible) {
3349 commitUidPendingStateLocked(uidState);
3350 }
3351 }
3352 }
3353 }
3354 }
3355
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003356 /**
3357 * Verify that package belongs to uid and return whether the package is privileged.
3358 *
3359 * @param uid The uid the package belongs to
3360 * @param packageName The package the might belong to the uid
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003361 * @param featureId The feature in the package or {@code null} if no need to verify
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003362 *
3363 * @return {@code true} iff the package is privileged
3364 */
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003365 private boolean verifyAndGetIsPrivileged(int uid, String packageName,
3366 @Nullable String featureId) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003367 if (uid == Process.ROOT_UID) {
3368 // For backwards compatibility, don't check package name for root UID.
3369 return false;
3370 }
3371
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003372 // Do not check if uid/packageName/featureId is already known
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003373 synchronized (this) {
3374 UidState uidState = mUidStates.get(uid);
3375 if (uidState != null && uidState.pkgOps != null) {
3376 Ops ops = uidState.pkgOps.get(packageName);
3377
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003378 if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003379 return ops.isPrivileged;
3380 }
3381 }
3382 }
3383
3384 boolean isPrivileged = false;
3385 final long ident = Binder.clearCallingIdentity();
3386 try {
3387 int pkgUid;
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003388 AndroidPackage pkg = LocalServices.getService(PackageManagerInternal.class).getPackage(
3389 packageName);
3390 boolean isFeatureIdValid = false;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003391
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003392 if (pkg != null) {
3393 if (featureId == null) {
3394 isFeatureIdValid = true;
3395 } else {
3396 if (pkg.getFeatures() != null) {
3397 int numFeatures = pkg.getFeatures().size();
3398 for (int i = 0; i < numFeatures; i++) {
3399 if (pkg.getFeatures().get(i).id.equals(featureId)) {
3400 isFeatureIdValid = true;
3401 }
3402 }
3403 }
3404 }
3405
3406 pkgUid = UserHandle.getUid(
3407 UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid()));
3408 isPrivileged = pkg.isPrivileged();
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003409 } else {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003410 // Allow any feature id for resolvable uids
3411 isFeatureIdValid = true;
3412
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003413 pkgUid = resolveUid(packageName);
3414 if (pkgUid >= 0) {
3415 isPrivileged = false;
3416 }
3417 }
3418 if (pkgUid != uid) {
3419 throw new SecurityException("Specified package " + packageName + " under uid " + uid
3420 + " but it is really " + pkgUid);
3421 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003422
3423 if (!isFeatureIdValid) {
3424 // TODO moltmann: Switch from logging to enforcement
3425 Slog.e(TAG, "featureId " + featureId + " not declared in manifest of "
3426 + packageName);
3427 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003428 } finally {
3429 Binder.restoreCallingIdentity(ident);
3430 }
3431
3432 return isPrivileged;
3433 }
3434
3435 /**
3436 * Get (and potentially create) ops.
3437 *
3438 * @param uid The uid the package belongs to
3439 * @param packageName The name of the package
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003440 * @param featureId The feature in the package
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003441 * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
3442 * @param edit If an ops does not exist, create the ops?
3443
3444 * @return
3445 */
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003446 private Ops getOpsRawLocked(int uid, String packageName, @Nullable String featureId,
3447 boolean isPrivileged, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07003448 UidState uidState = getUidStateLocked(uid, edit);
3449 if (uidState == null) {
3450 return null;
3451 }
3452
3453 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003454 if (!edit) {
3455 return null;
3456 }
Svet Ganov2af57082015-07-30 08:44:20 -07003457 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003458 }
Svet Ganov2af57082015-07-30 08:44:20 -07003459
3460 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003461 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003462 if (!edit) {
3463 return null;
3464 }
Svet Ganov2af57082015-07-30 08:44:20 -07003465 ops = new Ops(packageName, uidState, isPrivileged);
3466 uidState.pkgOps.put(packageName, ops);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003467 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003468 if (edit && featureId != null) {
3469 ops.knownFeatureIds.add(featureId);
3470 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08003471 return ops;
3472 }
3473
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003474 /**
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003475 * Get the state of all ops for a package.
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003476 *
3477 * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
3478 *
3479 * @param uid The uid the of the package
3480 * @param packageName The package name for which to get the state for
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003481 * @param featureId The feature in the package
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003482 * @param edit Iff {@code true} create the {@link Ops} object if not yet created
3483 * @param isPrivileged Whether the package is privileged or not
3484 *
3485 * @return The {@link Ops state} of all ops for the package
3486 */
3487 private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003488 @Nullable String featureId, boolean edit, boolean isPrivileged) {
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003489 UidState uidState = getUidStateLocked(uid, edit);
3490 if (uidState == null) {
3491 return null;
3492 }
3493
3494 if (uidState.pkgOps == null) {
3495 if (!edit) {
3496 return null;
3497 }
3498 uidState.pkgOps = new ArrayMap<>();
3499 }
3500
3501 Ops ops = uidState.pkgOps.get(packageName);
3502 if (ops == null) {
3503 if (!edit) {
3504 return null;
3505 }
3506 ops = new Ops(packageName, uidState, isPrivileged);
3507 uidState.pkgOps.put(packageName, ops);
3508 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003509
3510 if (edit && featureId != null) {
3511 ops.knownFeatureIds.add(featureId);
3512 }
3513
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003514 return ops;
3515 }
3516
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003517 private void scheduleWriteLocked() {
3518 if (!mWriteScheduled) {
3519 mWriteScheduled = true;
3520 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
3521 }
3522 }
3523
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003524 private void scheduleFastWriteLocked() {
3525 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003526 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003527 mFastWriteScheduled = true;
3528 mHandler.removeCallbacks(mWriteRunner);
3529 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003530 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003531 }
3532
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003533 /**
3534 * Get the state of an op for a uid.
3535 *
3536 * @param code The code of the op
3537 * @param uid The uid the of the package
3538 * @param packageName The package name for which to get the state for
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003539 * @param featureId The feature in the package
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003540 * @param isPrivileged Whether the package is privileged or not (only used if {@code edit
3541 * == true})
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003542 * @param edit Iff {@code true} create the {@link Op} object if not yet created
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003543 *
3544 * @return The {@link Op state} of the op
3545 */
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003546 private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003547 @Nullable String featureId, boolean isPrivileged, boolean edit) {
3548 Ops ops = getOpsRawNoVerifyLocked(uid, packageName, featureId, edit, isPrivileged);
Dianne Hackborn72e39832013-01-18 18:36:09 -08003549 if (ops == null) {
3550 return null;
3551 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003552 return getOpLocked(ops, code, uid, edit);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003553 }
3554
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003555 private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003556 Op op = ops.get(code);
3557 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003558 if (!edit) {
3559 return null;
3560 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003561 op = new Op(ops.uidState, ops.packageName, code, uid);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003562 ops.put(code, op);
3563 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003564 if (edit) {
3565 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08003566 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003567 return op;
3568 }
3569
Suprabh Shukla7e017922019-08-05 17:13:23 -07003570 private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
Suprabh Shuklab614a222019-09-12 14:42:46 -07003571 if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) {
3572 return false;
3573 }
Suprabh Shukla7e017922019-08-05 17:13:23 -07003574 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Suprabh Shuklab614a222019-09-12 14:42:46 -07003575 return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
Suprabh Shukla7e017922019-08-05 17:13:23 -07003576 }
3577
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003578 private boolean isOpRestrictedLocked(int uid, int code, String packageName,
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003579 @Nullable String featureId, boolean isPrivileged) {
Jason Monk62062992014-05-06 09:55:28 -04003580 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003581 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08003582
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003583 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08003584 // For each client, check that the given op is not restricted, or that the given
3585 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07003586 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07003587 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
3588 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
3589 // If we are the system, bypass user restrictions for certain codes
3590 synchronized (this) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003591 Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003592 true /* edit */);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07003593 if ((ops != null) && ops.isPrivileged) {
3594 return false;
3595 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08003596 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08003597 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08003598 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04003599 }
Jason Monk62062992014-05-06 09:55:28 -04003600 }
3601 return false;
3602 }
3603
Dianne Hackborn35654b62013-01-14 17:38:02 -08003604 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003605 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08003606 synchronized (mFile) {
3607 synchronized (this) {
3608 FileInputStream stream;
3609 try {
3610 stream = mFile.openRead();
3611 } catch (FileNotFoundException e) {
3612 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
3613 return;
3614 }
3615 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003616 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08003617 try {
3618 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01003619 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08003620 int type;
3621 while ((type = parser.next()) != XmlPullParser.START_TAG
3622 && type != XmlPullParser.END_DOCUMENT) {
3623 ;
3624 }
3625
3626 if (type != XmlPullParser.START_TAG) {
3627 throw new IllegalStateException("no start tag found");
3628 }
3629
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003630 final String versionString = parser.getAttributeValue(null, "v");
3631 if (versionString != null) {
3632 oldVersion = Integer.parseInt(versionString);
3633 }
3634
Dianne Hackborn35654b62013-01-14 17:38:02 -08003635 int outerDepth = parser.getDepth();
3636 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3637 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3638 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3639 continue;
3640 }
3641
3642 String tagName = parser.getName();
3643 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00003644 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07003645 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07003646 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08003647 } else {
3648 Slog.w(TAG, "Unknown element under <app-ops>: "
3649 + parser.getName());
3650 XmlUtils.skipCurrentTag(parser);
3651 }
3652 }
3653 success = true;
3654 } catch (IllegalStateException e) {
3655 Slog.w(TAG, "Failed parsing " + e);
3656 } catch (NullPointerException e) {
3657 Slog.w(TAG, "Failed parsing " + e);
3658 } catch (NumberFormatException e) {
3659 Slog.w(TAG, "Failed parsing " + e);
3660 } catch (XmlPullParserException e) {
3661 Slog.w(TAG, "Failed parsing " + e);
3662 } catch (IOException e) {
3663 Slog.w(TAG, "Failed parsing " + e);
3664 } catch (IndexOutOfBoundsException e) {
3665 Slog.w(TAG, "Failed parsing " + e);
3666 } finally {
3667 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07003668 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08003669 }
3670 try {
3671 stream.close();
3672 } catch (IOException e) {
3673 }
3674 }
3675 }
3676 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003677 synchronized (this) {
3678 upgradeLocked(oldVersion);
3679 }
3680 }
3681
3682 private void upgradeRunAnyInBackgroundLocked() {
3683 for (int i = 0; i < mUidStates.size(); i++) {
3684 final UidState uidState = mUidStates.valueAt(i);
3685 if (uidState == null) {
3686 continue;
3687 }
Hai Zhang93540ca2019-09-28 00:04:18 +00003688 if (uidState.opModes != null) {
3689 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
3690 if (idx >= 0) {
3691 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
3692 uidState.opModes.valueAt(idx));
3693 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003694 }
3695 if (uidState.pkgOps == null) {
3696 continue;
3697 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003698 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003699 for (int j = 0; j < uidState.pkgOps.size(); j++) {
3700 Ops ops = uidState.pkgOps.valueAt(j);
3701 if (ops != null) {
3702 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
3703 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003704 final Op copy = new Op(op.uidState, op.packageName,
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003705 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uidState.uid);
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003706 copy.mode = op.mode;
3707 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003708 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003709 }
3710 }
3711 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003712 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003713 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003714 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003715 }
3716 }
3717
3718 private void upgradeLocked(int oldVersion) {
3719 if (oldVersion >= CURRENT_VERSION) {
3720 return;
3721 }
3722 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
3723 switch (oldVersion) {
3724 case NO_VERSION:
3725 upgradeRunAnyInBackgroundLocked();
3726 // fall through
3727 case 1:
3728 // for future upgrades
3729 }
3730 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08003731 }
3732
Svet Ganovaf189e32019-02-15 18:45:29 -08003733 private void readUidOps(XmlPullParser parser) throws NumberFormatException,
Svet Ganov2af57082015-07-30 08:44:20 -07003734 XmlPullParserException, IOException {
3735 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
3736 int outerDepth = parser.getDepth();
3737 int type;
3738 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3739 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3740 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3741 continue;
3742 }
3743
3744 String tagName = parser.getName();
3745 if (tagName.equals("op")) {
3746 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
3747 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
3748 UidState uidState = getUidStateLocked(uid, true);
Hai Zhang93540ca2019-09-28 00:04:18 +00003749 if (uidState.opModes == null) {
3750 uidState.opModes = new SparseIntArray();
3751 }
3752 uidState.opModes.put(code, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07003753 } else {
3754 Slog.w(TAG, "Unknown element under <uid-ops>: "
3755 + parser.getName());
3756 XmlUtils.skipCurrentTag(parser);
3757 }
3758 }
3759 }
3760
Svet Ganovaf189e32019-02-15 18:45:29 -08003761 private void readPackage(XmlPullParser parser)
3762 throws NumberFormatException, XmlPullParserException, IOException {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003763 String pkgName = parser.getAttributeValue(null, "n");
3764 int outerDepth = parser.getDepth();
3765 int type;
3766 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3767 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3768 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3769 continue;
3770 }
3771
3772 String tagName = parser.getName();
3773 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00003774 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08003775 } else {
3776 Slog.w(TAG, "Unknown element under <pkg>: "
3777 + parser.getName());
3778 XmlUtils.skipCurrentTag(parser);
3779 }
3780 }
3781 }
3782
Svet Ganovaf189e32019-02-15 18:45:29 -08003783 private void readUid(XmlPullParser parser, String pkgName)
3784 throws NumberFormatException, XmlPullParserException, IOException {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003785 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Svet Ganovaf189e32019-02-15 18:45:29 -08003786 final UidState uidState = getUidStateLocked(uid, true);
Jason Monk1c7c3192014-06-26 12:52:18 -04003787 String isPrivilegedString = parser.getAttributeValue(null, "p");
3788 boolean isPrivileged = false;
3789 if (isPrivilegedString == null) {
3790 try {
3791 IPackageManager packageManager = ActivityThread.getPackageManager();
3792 if (packageManager != null) {
3793 ApplicationInfo appInfo = ActivityThread.getPackageManager()
3794 .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
3795 if (appInfo != null) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08003796 isPrivileged = (appInfo.privateFlags
3797 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
Jason Monk1c7c3192014-06-26 12:52:18 -04003798 }
3799 } else {
3800 // Could not load data, don't add to cache so it will be loaded later.
3801 return;
3802 }
3803 } catch (RemoteException e) {
3804 Slog.w(TAG, "Could not contact PackageManager", e);
3805 }
3806 } else {
3807 isPrivileged = Boolean.parseBoolean(isPrivilegedString);
3808 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08003809 int outerDepth = parser.getDepth();
3810 int type;
3811 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3812 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3813 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3814 continue;
3815 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08003816 String tagName = parser.getName();
3817 if (tagName.equals("op")) {
Svet Ganovaf189e32019-02-15 18:45:29 -08003818 readOp(parser, uidState, pkgName, isPrivileged);
Dianne Hackborn35654b62013-01-14 17:38:02 -08003819 } else {
3820 Slog.w(TAG, "Unknown element under <pkg>: "
3821 + parser.getName());
3822 XmlUtils.skipCurrentTag(parser);
3823 }
3824 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003825 uidState.evalForegroundOps(mOpModeWatchers);
3826 }
3827
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003828 private void readFeatureOp(XmlPullParser parser, @NonNull Op parent,
3829 @Nullable String feature) throws NumberFormatException, IOException {
3830 final FeatureOp featureOp = parent.getOrCreateFeature(parent, feature);
3831
3832 final long key = XmlUtils.readLongAttribute(parser, "n");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003833 final int uidState = extractUidStateFromKey(key);
3834 final int opFlags = extractFlagsFromKey(key);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003835
3836 final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0);
3837 final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003838 final long accessDuration = XmlUtils.readLongAttribute(parser, "d", -1);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003839 final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003840 final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", Process.INVALID_UID);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003841 final String proxyFeatureId = XmlUtils.readStringAttribute(parser, "pc");
3842
3843 if (accessTime > 0) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003844 featureOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg, proxyFeatureId,
3845 uidState, opFlags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003846 }
3847 if (rejectTime > 0) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003848 featureOp.rejected(rejectTime, uidState, opFlags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003849 }
3850 }
3851
Svet Ganovaf189e32019-02-15 18:45:29 -08003852 private void readOp(XmlPullParser parser, @NonNull UidState uidState,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003853 @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException,
3854 XmlPullParserException, IOException {
Svet Ganovaf189e32019-02-15 18:45:29 -08003855 Op op = new Op(uidState, pkgName,
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003856 Integer.parseInt(parser.getAttributeValue(null, "n")),
3857 uidState.uid);
Svet Ganovaf189e32019-02-15 18:45:29 -08003858
3859 final int mode = XmlUtils.readIntAttribute(parser, "m",
3860 AppOpsManager.opToDefaultMode(op.op));
3861 op.mode = mode;
3862
3863 int outerDepth = parser.getDepth();
3864 int type;
3865 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3866 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3867 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3868 continue;
3869 }
3870 String tagName = parser.getName();
3871 if (tagName.equals("st")) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003872 readFeatureOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
Svet Ganovaf189e32019-02-15 18:45:29 -08003873 } else {
3874 Slog.w(TAG, "Unknown element under <op>: "
3875 + parser.getName());
3876 XmlUtils.skipCurrentTag(parser);
3877 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003878 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003879
3880 if (uidState.pkgOps == null) {
3881 uidState.pkgOps = new ArrayMap<>();
3882 }
3883 Ops ops = uidState.pkgOps.get(pkgName);
3884 if (ops == null) {
3885 ops = new Ops(pkgName, uidState, isPrivileged);
3886 uidState.pkgOps.put(pkgName, ops);
3887 }
3888 ops.put(op.op, op);
Dianne Hackborn35654b62013-01-14 17:38:02 -08003889 }
3890
3891 void writeState() {
3892 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003893 FileOutputStream stream;
3894 try {
3895 stream = mFile.startWrite();
3896 } catch (IOException e) {
3897 Slog.w(TAG, "Failed to write state: " + e);
3898 return;
3899 }
3900
Dianne Hackborne17b4452018-01-10 13:15:40 -08003901 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
3902
Dianne Hackborn35654b62013-01-14 17:38:02 -08003903 try {
3904 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01003905 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08003906 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07003907 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07003908 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07003909
Hai Zhang93540ca2019-09-28 00:04:18 +00003910 SparseArray<SparseIntArray> uidStatesClone;
Eugene Susla463d5922019-07-17 18:14:15 -07003911 synchronized (this) {
Hai Zhang93540ca2019-09-28 00:04:18 +00003912 uidStatesClone = new SparseArray<>(mUidStates.size());
3913
3914 final int uidStateCount = mUidStates.size();
3915 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
3916 UidState uidState = mUidStates.valueAt(uidStateNum);
3917 int uid = mUidStates.keyAt(uidStateNum);
3918
3919 SparseIntArray opModes = uidState.opModes;
3920 if (opModes != null && opModes.size() > 0) {
3921 uidStatesClone.put(uid, new SparseIntArray(opModes.size()));
3922
3923 final int opCount = opModes.size();
3924 for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
3925 uidStatesClone.get(uid).put(
3926 opModes.keyAt(opCountNum),
3927 opModes.valueAt(opCountNum));
3928 }
Svet Ganov2af57082015-07-30 08:44:20 -07003929 }
Svet Ganov2af57082015-07-30 08:44:20 -07003930 }
3931 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08003932
Hai Zhang93540ca2019-09-28 00:04:18 +00003933 final int uidStateCount = uidStatesClone.size();
3934 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
3935 SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
3936 if (opModes != null && opModes.size() > 0) {
3937 out.startTag(null, "uid");
3938 out.attribute(null, "n",
3939 Integer.toString(uidStatesClone.keyAt(uidStateNum)));
3940 final int opCount = opModes.size();
3941 for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
3942 final int op = opModes.keyAt(opCountNum);
3943 final int mode = opModes.valueAt(opCountNum);
3944 out.startTag(null, "op");
3945 out.attribute(null, "n", Integer.toString(op));
3946 out.attribute(null, "m", Integer.toString(mode));
3947 out.endTag(null, "op");
3948 }
3949 out.endTag(null, "uid");
Eugene Susla11b706c2019-08-28 14:28:32 -07003950 }
3951 }
3952
Dianne Hackborn35654b62013-01-14 17:38:02 -08003953 if (allOps != null) {
3954 String lastPkg = null;
3955 for (int i=0; i<allOps.size(); i++) {
3956 AppOpsManager.PackageOps pkg = allOps.get(i);
3957 if (!pkg.getPackageName().equals(lastPkg)) {
3958 if (lastPkg != null) {
3959 out.endTag(null, "pkg");
3960 }
3961 lastPkg = pkg.getPackageName();
3962 out.startTag(null, "pkg");
3963 out.attribute(null, "n", lastPkg);
3964 }
3965 out.startTag(null, "uid");
3966 out.attribute(null, "n", Integer.toString(pkg.getUid()));
Jason Monk1c7c3192014-06-26 12:52:18 -04003967 synchronized (this) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003968 Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), null,
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003969 false /* isPrivileged */, false /* edit */);
Jason Monk1c7c3192014-06-26 12:52:18 -04003970 // Should always be present as the list of PackageOps is generated
3971 // from Ops.
3972 if (ops != null) {
3973 out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
3974 } else {
3975 out.attribute(null, "p", Boolean.toString(false));
3976 }
3977 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08003978 List<AppOpsManager.OpEntry> ops = pkg.getOps();
3979 for (int j=0; j<ops.size(); j++) {
3980 AppOpsManager.OpEntry op = ops.get(j);
3981 out.startTag(null, "op");
3982 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07003983 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003984 out.attribute(null, "m", Integer.toString(op.getMode()));
3985 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003986
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003987 for (String featureId : op.getFeatures().keySet()) {
3988 final OpFeatureEntry feature = op.getFeatures().get(
3989 featureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08003990
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003991 final ArraySet<Long> keys = feature.collectKeys();
Svet Ganovaf189e32019-02-15 18:45:29 -08003992
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003993 final int keyCount = keys.size();
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003994 for (int k = 0; k < keyCount; k++) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08003995 final long key = keys.valueAt(k);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003996
3997 final int uidState = AppOpsManager.extractUidStateFromKey(key);
3998 final int flags = AppOpsManager.extractFlagsFromKey(key);
3999
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004000 final long accessTime = feature.getLastAccessTime(uidState,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004001 uidState, flags);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004002 final long rejectTime = feature.getLastRejectTime(uidState,
4003 uidState, flags);
4004 final long accessDuration = feature.getLastDuration(uidState,
4005 uidState, flags);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004006 // Proxy information for rejections is not backed up
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004007 final OpEventProxyInfo proxy = feature.getLastProxyInfo(
4008 uidState, uidState, flags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004009
4010 if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004011 && proxy == null) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004012 continue;
4013 }
4014
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004015 String proxyPkg = null;
4016 String proxyFeatureId = null;
4017 int proxyUid = Process.INVALID_UID;
4018 if (proxy != null) {
4019 proxyPkg = proxy.getPackageName();
4020 proxyFeatureId = proxy.getFeatureId();
4021 proxyUid = proxy.getUid();
4022 }
4023
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004024 out.startTag(null, "st");
4025 if (featureId != null) {
4026 out.attribute(null, "id", featureId);
4027 }
4028 out.attribute(null, "n", Long.toString(key));
4029 if (accessTime > 0) {
4030 out.attribute(null, "t", Long.toString(accessTime));
4031 }
4032 if (rejectTime > 0) {
4033 out.attribute(null, "r", Long.toString(rejectTime));
4034 }
4035 if (accessDuration > 0) {
4036 out.attribute(null, "d", Long.toString(accessDuration));
4037 }
4038 if (proxyPkg != null) {
4039 out.attribute(null, "pp", proxyPkg);
4040 }
4041 if (proxyFeatureId != null) {
4042 out.attribute(null, "pc", proxyFeatureId);
4043 }
4044 if (proxyUid >= 0) {
4045 out.attribute(null, "pu", Integer.toString(proxyUid));
4046 }
4047 out.endTag(null, "st");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004048 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08004049 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004050
Dianne Hackborn35654b62013-01-14 17:38:02 -08004051 out.endTag(null, "op");
4052 }
4053 out.endTag(null, "uid");
4054 }
4055 if (lastPkg != null) {
4056 out.endTag(null, "pkg");
4057 }
4058 }
4059
4060 out.endTag(null, "app-ops");
4061 out.endDocument();
4062 mFile.finishWrite(stream);
4063 } catch (IOException e) {
4064 Slog.w(TAG, "Failed to write state, restoring backup.", e);
4065 mFile.failWrite(stream);
4066 }
4067 }
4068 }
4069
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004070 static class Shell extends ShellCommand {
4071 final IAppOpsService mInterface;
4072 final AppOpsService mInternal;
4073
4074 int userId = UserHandle.USER_SYSTEM;
4075 String packageName;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004076 String featureId;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004077 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004078 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004079 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004080 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004081 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004082 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004083 final static Binder sBinder = new Binder();
4084 IBinder mToken;
Svet Ganovd563e932019-04-14 13:07:41 -07004085 boolean targetsUid;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004086
4087 Shell(IAppOpsService iface, AppOpsService internal) {
4088 mInterface = iface;
4089 mInternal = internal;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004090 mToken = AppOpsManager.getClientId();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004091 }
4092
4093 @Override
4094 public int onCommand(String cmd) {
4095 return onShellCommand(this, cmd);
4096 }
4097
4098 @Override
4099 public void onHelp() {
4100 PrintWriter pw = getOutPrintWriter();
4101 dumpCommandHelp(pw);
4102 }
4103
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004104 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004105 try {
4106 return AppOpsManager.strOpToOp(op);
4107 } catch (IllegalArgumentException e) {
4108 }
4109 try {
4110 return Integer.parseInt(op);
4111 } catch (NumberFormatException e) {
4112 }
4113 try {
4114 return AppOpsManager.strDebugOpToOp(op);
4115 } catch (IllegalArgumentException e) {
4116 err.println("Error: " + e.getMessage());
4117 return -1;
4118 }
4119 }
4120
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004121 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004122 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
4123 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004124 return i;
4125 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004126 }
4127 try {
4128 return Integer.parseInt(modeStr);
4129 } catch (NumberFormatException e) {
4130 }
4131 err.println("Error: Mode " + modeStr + " is not valid");
4132 return -1;
4133 }
4134
4135 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
4136 userId = UserHandle.USER_CURRENT;
4137 opStr = null;
4138 modeStr = null;
4139 for (String argument; (argument = getNextArg()) != null;) {
4140 if ("--user".equals(argument)) {
4141 userId = UserHandle.parseUserArg(getNextArgRequired());
4142 } else {
4143 if (opStr == null) {
4144 opStr = argument;
4145 } else if (modeStr == null) {
4146 modeStr = argument;
4147 break;
4148 }
4149 }
4150 }
4151 if (opStr == null) {
4152 err.println("Error: Operation not specified.");
4153 return -1;
4154 }
4155 op = strOpToOp(opStr, err);
4156 if (op < 0) {
4157 return -1;
4158 }
4159 if (modeStr != null) {
4160 if ((mode=strModeToMode(modeStr, err)) < 0) {
4161 return -1;
4162 }
4163 } else {
4164 mode = defMode;
4165 }
4166 return 0;
4167 }
4168
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004169 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
4170 userId = UserHandle.USER_CURRENT;
4171 packageName = null;
4172 opStr = null;
4173 for (String argument; (argument = getNextArg()) != null;) {
4174 if ("--user".equals(argument)) {
4175 userId = UserHandle.parseUserArg(getNextArgRequired());
Svet Ganovd563e932019-04-14 13:07:41 -07004176 } else if ("--uid".equals(argument)) {
4177 targetsUid = true;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004178 } else if ("--feature".equals(argument)) {
4179 featureId = getNextArgRequired();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004180 } else {
4181 if (packageName == null) {
4182 packageName = argument;
4183 } else if (opStr == null) {
4184 opStr = argument;
4185 break;
4186 }
4187 }
4188 }
4189 if (packageName == null) {
4190 err.println("Error: Package name not specified.");
4191 return -1;
4192 } else if (opStr == null && reqOp) {
4193 err.println("Error: Operation not specified.");
4194 return -1;
4195 }
4196 if (opStr != null) {
4197 op = strOpToOp(opStr, err);
4198 if (op < 0) {
4199 return -1;
4200 }
4201 } else {
4202 op = AppOpsManager.OP_NONE;
4203 }
4204 if (userId == UserHandle.USER_CURRENT) {
4205 userId = ActivityManager.getCurrentUser();
4206 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004207 nonpackageUid = -1;
4208 try {
4209 nonpackageUid = Integer.parseInt(packageName);
4210 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004211 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004212 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
4213 && packageName.indexOf('.') < 0) {
4214 int i = 1;
4215 while (i < packageName.length() && packageName.charAt(i) >= '0'
4216 && packageName.charAt(i) <= '9') {
4217 i++;
4218 }
4219 if (i > 1 && i < packageName.length()) {
4220 String userStr = packageName.substring(1, i);
4221 try {
4222 int user = Integer.parseInt(userStr);
4223 char type = packageName.charAt(i);
4224 i++;
4225 int startTypeVal = i;
4226 while (i < packageName.length() && packageName.charAt(i) >= '0'
4227 && packageName.charAt(i) <= '9') {
4228 i++;
4229 }
4230 if (i > startTypeVal) {
4231 String typeValStr = packageName.substring(startTypeVal, i);
4232 try {
4233 int typeVal = Integer.parseInt(typeValStr);
4234 if (type == 'a') {
4235 nonpackageUid = UserHandle.getUid(user,
4236 typeVal + Process.FIRST_APPLICATION_UID);
4237 } else if (type == 's') {
4238 nonpackageUid = UserHandle.getUid(user, typeVal);
4239 }
4240 } catch (NumberFormatException e) {
4241 }
4242 }
4243 } catch (NumberFormatException e) {
4244 }
4245 }
4246 }
4247 if (nonpackageUid != -1) {
4248 packageName = null;
4249 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08004250 packageUid = resolveUid(packageName);
4251 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004252 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
4253 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
4254 }
4255 if (packageUid < 0) {
4256 err.println("Error: No UID for " + packageName + " in user " + userId);
4257 return -1;
4258 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004259 }
4260 return 0;
4261 }
4262 }
4263
4264 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07004265 FileDescriptor err, String[] args, ShellCallback callback,
4266 ResultReceiver resultReceiver) {
4267 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004268 }
4269
4270 static void dumpCommandHelp(PrintWriter pw) {
4271 pw.println("AppOps service (appops) commands:");
4272 pw.println(" help");
4273 pw.println(" Print this help text.");
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004274 pw.println(" start [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> <OP> ");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004275 pw.println(" Starts a given operation for a particular application.");
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004276 pw.println(" stop [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> <OP> ");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004277 pw.println(" Stops a given operation for a particular application.");
Svet Ganovb687fad2019-04-30 17:32:44 -07004278 pw.println(" set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004279 pw.println(" Set the mode for a particular application and operation.");
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004280 pw.println(" get [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> [<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004281 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004282 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
4283 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004284 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
4285 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004286 pw.println(" write-settings");
4287 pw.println(" Immediately write pending changes to storage.");
4288 pw.println(" read-settings");
4289 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004290 pw.println(" options:");
Svet Ganovb687fad2019-04-30 17:32:44 -07004291 pw.println(" <PACKAGE> an Android package name or its UID if prefixed by --uid");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004292 pw.println(" <OP> an AppOps operation.");
4293 pw.println(" <MODE> one of allow, ignore, deny, or default");
4294 pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
4295 pw.println(" specified, the current user is assumed.");
4296 }
4297
4298 static int onShellCommand(Shell shell, String cmd) {
4299 if (cmd == null) {
4300 return shell.handleDefaultCommands(cmd);
4301 }
4302 PrintWriter pw = shell.getOutPrintWriter();
4303 PrintWriter err = shell.getErrPrintWriter();
4304 try {
4305 switch (cmd) {
4306 case "set": {
4307 int res = shell.parseUserPackageOp(true, err);
4308 if (res < 0) {
4309 return res;
4310 }
4311 String modeStr = shell.getNextArg();
4312 if (modeStr == null) {
4313 err.println("Error: Mode not specified.");
4314 return -1;
4315 }
4316
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004317 final int mode = shell.strModeToMode(modeStr, err);
4318 if (mode < 0) {
4319 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004320 }
4321
Svet Ganovd563e932019-04-14 13:07:41 -07004322 if (!shell.targetsUid && shell.packageName != null) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004323 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
4324 mode);
Svet Ganovd563e932019-04-14 13:07:41 -07004325 } else if (shell.targetsUid && shell.packageName != null) {
4326 try {
4327 final int uid = shell.mInternal.mContext.getPackageManager()
4328 .getPackageUid(shell.packageName, shell.userId);
4329 shell.mInterface.setUidMode(shell.op, uid, mode);
4330 } catch (PackageManager.NameNotFoundException e) {
4331 return -1;
4332 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004333 } else {
4334 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
4335 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004336 return 0;
4337 }
4338 case "get": {
4339 int res = shell.parseUserPackageOp(false, err);
4340 if (res < 0) {
4341 return res;
4342 }
4343
Eugene Suslae4ee2c22018-11-05 12:23:30 -08004344 List<AppOpsManager.PackageOps> ops = new ArrayList<>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004345 if (shell.packageName != null) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08004346 // Uid mode overrides package mode, so make sure it's also reported
4347 List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
4348 shell.packageUid,
4349 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
4350 if (r != null) {
4351 ops.addAll(r);
4352 }
4353 r = shell.mInterface.getOpsForPackage(
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004354 shell.packageUid, shell.packageName,
4355 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
Eugene Suslae4ee2c22018-11-05 12:23:30 -08004356 if (r != null) {
4357 ops.addAll(r);
4358 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004359 } else {
4360 ops = shell.mInterface.getUidOps(
4361 shell.nonpackageUid,
4362 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
4363 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004364 if (ops == null || ops.size() <= 0) {
4365 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08004366 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004367 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08004368 AppOpsManager.opToDefaultMode(shell.op)));
4369 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004370 return 0;
4371 }
4372 final long now = System.currentTimeMillis();
4373 for (int i=0; i<ops.size(); i++) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08004374 AppOpsManager.PackageOps packageOps = ops.get(i);
4375 if (packageOps.getPackageName() == null) {
4376 pw.print("Uid mode: ");
4377 }
4378 List<AppOpsManager.OpEntry> entries = packageOps.getOps();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004379 for (int j=0; j<entries.size(); j++) {
4380 AppOpsManager.OpEntry ent = entries.get(j);
4381 pw.print(AppOpsManager.opToName(ent.getOp()));
4382 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004383 pw.print(AppOpsManager.modeToName(ent.getMode()));
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004384 if (shell.featureId == null) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004385 if (ent.getLastAccessTime(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004386 pw.print("; time=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004387 TimeUtils.formatDuration(
4388 now - ent.getLastAccessTime(OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004389 pw.print(" ago");
4390 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004391 if (ent.getLastRejectTime(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004392 pw.print("; rejectTime=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004393 TimeUtils.formatDuration(
4394 now - ent.getLastRejectTime(OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004395 pw.print(" ago");
4396 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004397 if (ent.isRunning()) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004398 pw.print(" (running)");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004399 } else if (ent.getLastDuration(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004400 pw.print("; duration=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004401 TimeUtils.formatDuration(ent.getLastDuration(OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004402 }
4403 } else {
4404 final OpFeatureEntry featureEnt = ent.getFeatures().get(
4405 shell.featureId);
4406 if (featureEnt != null) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004407 if (featureEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004408 pw.print("; time=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004409 TimeUtils.formatDuration(now - featureEnt.getLastAccessTime(
4410 OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004411 pw.print(" ago");
4412 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004413 if (featureEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004414 pw.print("; rejectTime=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004415 TimeUtils.formatDuration(
4416 now - featureEnt.getLastRejectTime(OP_FLAGS_ALL),
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004417 pw);
4418 pw.print(" ago");
4419 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004420 if (featureEnt.isRunning()) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004421 pw.print(" (running)");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004422 } else if (featureEnt.getLastDuration(OP_FLAGS_ALL)
4423 != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004424 pw.print("; duration=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004425 TimeUtils.formatDuration(
4426 featureEnt.getLastDuration(OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004427 }
4428 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004429 }
4430 pw.println();
4431 }
4432 }
4433 return 0;
4434 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004435 case "query-op": {
4436 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
4437 if (res < 0) {
4438 return res;
4439 }
4440 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
4441 new int[] {shell.op});
4442 if (ops == null || ops.size() <= 0) {
4443 pw.println("No operations.");
4444 return 0;
4445 }
4446 for (int i=0; i<ops.size(); i++) {
4447 final AppOpsManager.PackageOps pkg = ops.get(i);
4448 boolean hasMatch = false;
4449 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
4450 for (int j=0; j<entries.size(); j++) {
4451 AppOpsManager.OpEntry ent = entries.get(j);
4452 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
4453 hasMatch = true;
4454 break;
4455 }
4456 }
4457 if (hasMatch) {
4458 pw.println(pkg.getPackageName());
4459 }
4460 }
4461 return 0;
4462 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004463 case "reset": {
4464 String packageName = null;
4465 int userId = UserHandle.USER_CURRENT;
4466 for (String argument; (argument = shell.getNextArg()) != null;) {
4467 if ("--user".equals(argument)) {
4468 String userStr = shell.getNextArgRequired();
4469 userId = UserHandle.parseUserArg(userStr);
4470 } else {
4471 if (packageName == null) {
4472 packageName = argument;
4473 } else {
4474 err.println("Error: Unsupported argument: " + argument);
4475 return -1;
4476 }
4477 }
4478 }
4479
4480 if (userId == UserHandle.USER_CURRENT) {
4481 userId = ActivityManager.getCurrentUser();
4482 }
4483
4484 shell.mInterface.resetAllModes(userId, packageName);
4485 pw.print("Reset all modes for: ");
4486 if (userId == UserHandle.USER_ALL) {
4487 pw.print("all users");
4488 } else {
4489 pw.print("user "); pw.print(userId);
4490 }
4491 pw.print(", ");
4492 if (packageName == null) {
4493 pw.println("all packages");
4494 } else {
4495 pw.print("package "); pw.println(packageName);
4496 }
4497 return 0;
4498 }
4499 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07004500 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
4501 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004502 long token = Binder.clearCallingIdentity();
4503 try {
4504 synchronized (shell.mInternal) {
4505 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
4506 }
4507 shell.mInternal.writeState();
4508 pw.println("Current settings written.");
4509 } finally {
4510 Binder.restoreCallingIdentity(token);
4511 }
4512 return 0;
4513 }
4514 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07004515 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
4516 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004517 long token = Binder.clearCallingIdentity();
4518 try {
4519 shell.mInternal.readState();
4520 pw.println("Last settings read.");
4521 } finally {
4522 Binder.restoreCallingIdentity(token);
4523 }
4524 return 0;
4525 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004526 case "start": {
4527 int res = shell.parseUserPackageOp(true, err);
4528 if (res < 0) {
4529 return res;
4530 }
4531
4532 if (shell.packageName != null) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004533 shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08004534 shell.packageName, shell.featureId, true, true,
4535 "appops start shell command");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004536 } else {
4537 return -1;
4538 }
4539 return 0;
4540 }
4541 case "stop": {
4542 int res = shell.parseUserPackageOp(true, err);
4543 if (res < 0) {
4544 return res;
4545 }
4546
4547 if (shell.packageName != null) {
4548 shell.mInterface.finishOperation(shell.mToken,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004549 shell.op, shell.packageUid, shell.packageName, shell.featureId);
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004550 } else {
4551 return -1;
4552 }
4553 return 0;
4554 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004555 default:
4556 return shell.handleDefaultCommands(cmd);
4557 }
4558 } catch (RemoteException e) {
4559 pw.println("Remote exception: " + e);
4560 }
4561 return -1;
4562 }
4563
4564 private void dumpHelp(PrintWriter pw) {
4565 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004566 pw.println(" -h");
4567 pw.println(" Print this help text.");
4568 pw.println(" --op [OP]");
4569 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004570 pw.println(" --mode [MODE]");
4571 pw.println(" Limit output to data associated with the given app op mode.");
4572 pw.println(" --package [PACKAGE]");
4573 pw.println(" Limit output to data associated with the given package name.");
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004574 pw.println(" --featureId [featureId]");
4575 pw.println(" Limit output to data associated with the given feature id.");
Dianne Hackborn125dc532019-01-09 13:31:48 -08004576 pw.println(" --watchers");
4577 pw.println(" Only output the watcher sections.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004578 }
4579
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004580 private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterFeatureId,
4581 @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now,
4582 @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004583 final int numFeatures = op.mFeatures.size();
4584 for (int i = 0; i < numFeatures; i++) {
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004585 if ((filter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(op.mFeatures.keyAt(i),
4586 filterFeatureId)) {
4587 continue;
4588 }
4589
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004590 pw.print(prefix + op.mFeatures.keyAt(i) + "=[\n");
4591 dumpStatesLocked(pw, nowElapsed, op, op.mFeatures.keyAt(i), now, sdf, date,
4592 prefix + " ");
4593 pw.print(prefix + "]\n");
4594 }
4595 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004596
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004597 private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
4598 @Nullable String featureId, long now, @NonNull SimpleDateFormat sdf,
4599 @NonNull Date date, @NonNull String prefix) {
4600
4601 final OpFeatureEntry entry = op.createSingleFeatureEntryLocked(
4602 featureId).getFeatures().get(featureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08004603
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004604 final ArraySet<Long> keys = entry.collectKeys();
Svet Ganovaf189e32019-02-15 18:45:29 -08004605
4606 final int keyCount = keys.size();
4607 for (int k = 0; k < keyCount; k++) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004608 final long key = keys.valueAt(k);
Svet Ganovaf189e32019-02-15 18:45:29 -08004609
4610 final int uidState = AppOpsManager.extractUidStateFromKey(key);
4611 final int flags = AppOpsManager.extractFlagsFromKey(key);
4612
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004613 final long accessTime = entry.getLastAccessTime(uidState, uidState, flags);
4614 final long rejectTime = entry.getLastRejectTime(uidState, uidState, flags);
4615 final long accessDuration = entry.getLastDuration(uidState, uidState, flags);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004616 final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
4617
4618 String proxyPkg = null;
4619 String proxyFeatureId = null;
4620 int proxyUid = Process.INVALID_UID;
4621 if (proxy != null) {
4622 proxyPkg = proxy.getPackageName();
4623 proxyFeatureId = proxy.getFeatureId();
4624 proxyUid = proxy.getUid();
4625 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004626
4627 if (accessTime > 0) {
4628 pw.print(prefix);
4629 pw.print("Access: ");
4630 pw.print(AppOpsManager.keyToString(key));
4631 pw.print(" ");
4632 date.setTime(accessTime);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004633 pw.print(sdf.format(date));
4634 pw.print(" (");
Svet Ganovaf189e32019-02-15 18:45:29 -08004635 TimeUtils.formatDuration(accessTime - now, pw);
4636 pw.print(")");
4637 if (accessDuration > 0) {
4638 pw.print(" duration=");
4639 TimeUtils.formatDuration(accessDuration, pw);
4640 }
4641 if (proxyUid >= 0) {
4642 pw.print(" proxy[");
4643 pw.print("uid=");
4644 pw.print(proxyUid);
4645 pw.print(", pkg=");
4646 pw.print(proxyPkg);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004647 pw.print(", feature=");
4648 pw.print(proxyFeatureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08004649 pw.print("]");
4650 }
4651 pw.println();
4652 }
4653
4654 if (rejectTime > 0) {
4655 pw.print(prefix);
4656 pw.print("Reject: ");
4657 pw.print(AppOpsManager.keyToString(key));
4658 date.setTime(rejectTime);
4659 pw.print(sdf.format(date));
4660 pw.print(" (");
4661 TimeUtils.formatDuration(rejectTime - now, pw);
4662 pw.print(")");
4663 if (proxyUid >= 0) {
4664 pw.print(" proxy[");
4665 pw.print("uid=");
4666 pw.print(proxyUid);
4667 pw.print(", pkg=");
4668 pw.print(proxyPkg);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004669 pw.print(", feature=");
4670 pw.print(proxyFeatureId);
Svet Ganovaf189e32019-02-15 18:45:29 -08004671 pw.print("]");
4672 }
4673 pw.println();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004674 }
4675 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004676
4677 final FeatureOp featureOp = op.mFeatures.get(featureId);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004678 if (featureOp.isRunning()) {
Philip P. Moltmanne6ece902020-01-02 13:31:10 -08004679 long earliestElapsedTime = Long.MAX_VALUE;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004680 long maxNumStarts = 0;
4681 int numInProgressEvents = featureOp.mInProgressEvents.size();
4682 for (int i = 0; i < numInProgressEvents; i++) {
4683 InProgressStartOpEvent event = featureOp.mInProgressEvents.valueAt(i);
4684
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08004685 earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004686 maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts);
4687 }
4688
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004689 pw.print(prefix + "Running start at: ");
Philip P. Moltmanne6ece902020-01-02 13:31:10 -08004690 TimeUtils.formatDuration(nowElapsed - earliestElapsedTime, pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004691 pw.println();
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004692
4693 if (maxNumStarts > 1) {
4694 pw.print(prefix + "startNesting=");
4695 pw.println(maxNumStarts);
4696 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004697 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004698 }
4699
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004700 @Override
4701 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06004702 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004703
Svet Ganov8455ba22019-01-02 13:05:56 -08004704 int dumpOp = OP_NONE;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004705 String dumpPackage = null;
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004706 String dumpFeatureId = null;
Svet Ganov8455ba22019-01-02 13:05:56 -08004707 int dumpUid = Process.INVALID_UID;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004708 int dumpMode = -1;
Dianne Hackborn125dc532019-01-09 13:31:48 -08004709 boolean dumpWatchers = false;
Nate Myren697650b2020-01-23 13:25:06 -08004710 // TODO ntmyren: Remove the dumpHistory and dumpFilter
Svet Ganovaf189e32019-02-15 18:45:29 -08004711 boolean dumpHistory = false;
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004712 @HistoricalOpsRequestFilter int dumpFilter = 0;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004713
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004714 if (args != null) {
4715 for (int i=0; i<args.length; i++) {
4716 String arg = args[i];
4717 if ("-h".equals(arg)) {
4718 dumpHelp(pw);
4719 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07004720 } else if ("-a".equals(arg)) {
4721 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004722 } else if ("--op".equals(arg)) {
4723 i++;
4724 if (i >= args.length) {
4725 pw.println("No argument for --op option");
4726 return;
4727 }
4728 dumpOp = Shell.strOpToOp(args[i], pw);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004729 dumpFilter |= FILTER_BY_OP_NAMES;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004730 if (dumpOp < 0) {
4731 return;
4732 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004733 } else if ("--package".equals(arg)) {
4734 i++;
4735 if (i >= args.length) {
4736 pw.println("No argument for --package option");
4737 return;
4738 }
4739 dumpPackage = args[i];
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004740 dumpFilter |= FILTER_BY_PACKAGE_NAME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004741 try {
4742 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
4743 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
4744 0);
4745 } catch (RemoteException e) {
4746 }
4747 if (dumpUid < 0) {
4748 pw.println("Unknown package: " + dumpPackage);
4749 return;
4750 }
4751 dumpUid = UserHandle.getAppId(dumpUid);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004752 dumpFilter |= FILTER_BY_UID;
4753 } else if ("--featureId".equals(arg)) {
4754 i++;
4755 if (i >= args.length) {
4756 pw.println("No argument for --featureId option");
4757 return;
4758 }
4759 dumpFeatureId = args[i];
4760 dumpFilter |= FILTER_BY_FEATURE_ID;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004761 } else if ("--mode".equals(arg)) {
4762 i++;
4763 if (i >= args.length) {
4764 pw.println("No argument for --mode option");
4765 return;
4766 }
4767 dumpMode = Shell.strModeToMode(args[i], pw);
4768 if (dumpMode < 0) {
4769 return;
4770 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08004771 } else if ("--watchers".equals(arg)) {
4772 dumpWatchers = true;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004773 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
4774 pw.println("Unknown option: " + arg);
4775 return;
4776 } else {
4777 pw.println("Unknown command: " + arg);
4778 return;
4779 }
4780 }
4781 }
4782
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004783 synchronized (this) {
4784 pw.println("Current AppOps Service state:");
Svet Ganovaf189e32019-02-15 18:45:29 -08004785 if (!dumpHistory && !dumpWatchers) {
4786 mConstants.dump(pw);
4787 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004788 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08004789 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004790 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004791 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004792 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
4793 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004794 boolean needSep = false;
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004795 if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers
4796 && !dumpHistory) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07004797 pw.println(" Profile owners:");
4798 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
4799 pw.print(" User #");
4800 pw.print(mProfileOwners.keyAt(poi));
4801 pw.print(": ");
4802 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
4803 pw.println();
4804 }
4805 pw.println();
4806 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004807 if (mOpModeWatchers.size() > 0 && !dumpHistory) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004808 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004809 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004810 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
4811 continue;
4812 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004813 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004814 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004815 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004816 final ModeCallback cb = callbacks.valueAt(j);
Dianne Hackborn125dc532019-01-09 13:31:48 -08004817 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004818 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
4819 continue;
4820 }
4821 needSep = true;
4822 if (!printedHeader) {
4823 pw.println(" Op mode watchers:");
4824 printedHeader = true;
4825 }
4826 if (!printedOpHeader) {
4827 pw.print(" Op ");
4828 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
4829 pw.println(":");
4830 printedOpHeader = true;
4831 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004832 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004833 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004834 }
4835 }
4836 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004837 if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004838 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004839 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004840 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
4841 continue;
4842 }
4843 needSep = true;
4844 if (!printedHeader) {
4845 pw.println(" Package mode watchers:");
4846 printedHeader = true;
4847 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004848 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
4849 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004850 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004851 for (int j=0; j<callbacks.size(); j++) {
4852 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08004853 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004854 }
4855 }
4856 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004857 if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004858 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004859 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004860 final ModeCallback cb = mModeWatchers.valueAt(i);
Dianne Hackborn125dc532019-01-09 13:31:48 -08004861 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004862 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
4863 continue;
4864 }
4865 needSep = true;
4866 if (!printedHeader) {
4867 pw.println(" All op mode watchers:");
4868 printedHeader = true;
4869 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07004870 pw.print(" ");
4871 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004872 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004873 }
4874 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004875 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004876 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004877 boolean printedHeader = false;
Philip P. Moltmannba136462019-05-21 10:20:38 -07004878 for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
4879 final SparseArray<ActiveCallback> activeWatchers =
4880 mActiveWatchers.valueAt(watcherNum);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004881 if (activeWatchers.size() <= 0) {
4882 continue;
4883 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004884 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004885 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
4886 continue;
4887 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08004888 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004889 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
4890 continue;
4891 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004892 if (!printedHeader) {
4893 pw.println(" All op active watchers:");
4894 printedHeader = true;
4895 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07004896 pw.print(" ");
4897 pw.print(Integer.toHexString(System.identityHashCode(
Philip P. Moltmannba136462019-05-21 10:20:38 -07004898 mActiveWatchers.keyAt(watcherNum))));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07004899 pw.println(" ->");
4900 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004901 final int opCount = activeWatchers.size();
Philip P. Moltmannba136462019-05-21 10:20:38 -07004902 for (int opNum = 0; opNum < opCount; opNum++) {
4903 if (opNum > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004904 pw.print(' ');
4905 }
Philip P. Moltmannba136462019-05-21 10:20:38 -07004906 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
4907 if (opNum < opCount - 1) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004908 pw.print(',');
4909 }
4910 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07004911 pw.println("]");
4912 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004913 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08004914 }
4915 }
Svet Ganovb3d2ae22018-12-17 22:06:15 -08004916 if (mNotedWatchers.size() > 0 && dumpMode < 0) {
4917 needSep = true;
4918 boolean printedHeader = false;
4919 for (int i = 0; i < mNotedWatchers.size(); i++) {
4920 final SparseArray<NotedCallback> notedWatchers = mNotedWatchers.valueAt(i);
4921 if (notedWatchers.size() <= 0) {
4922 continue;
4923 }
4924 final NotedCallback cb = notedWatchers.valueAt(0);
4925 if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
4926 continue;
4927 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08004928 if (dumpPackage != null
Svet Ganovb3d2ae22018-12-17 22:06:15 -08004929 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
4930 continue;
4931 }
4932 if (!printedHeader) {
4933 pw.println(" All op noted watchers:");
4934 printedHeader = true;
4935 }
4936 pw.print(" ");
4937 pw.print(Integer.toHexString(System.identityHashCode(
4938 mNotedWatchers.keyAt(i))));
4939 pw.println(" ->");
4940 pw.print(" [");
4941 final int opCount = notedWatchers.size();
4942 for (i = 0; i < opCount; i++) {
4943 if (i > 0) {
4944 pw.print(' ');
4945 }
4946 pw.print(AppOpsManager.opToName(notedWatchers.keyAt(i)));
4947 if (i < opCount - 1) {
4948 pw.print(',');
4949 }
4950 }
4951 pw.println("]");
4952 pw.print(" ");
4953 pw.println(cb);
4954 }
4955 }
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07004956 if (mAudioRestrictionManager.hasActiveRestrictions() && dumpOp < 0
4957 && dumpPackage != null && dumpMode < 0 && !dumpWatchers && !dumpWatchers) {
4958 needSep = mAudioRestrictionManager.dump(pw) | needSep ;
John Spurlock1af30c72014-03-10 08:33:35 -04004959 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07004960 if (needSep) {
4961 pw.println();
4962 }
Svet Ganov2af57082015-07-30 08:44:20 -07004963 for (int i=0; i<mUidStates.size(); i++) {
4964 UidState uidState = mUidStates.valueAt(i);
Hai Zhang93540ca2019-09-28 00:04:18 +00004965 final SparseIntArray opModes = uidState.opModes;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004966 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
4967
Svet Ganovaf189e32019-02-15 18:45:29 -08004968 if (dumpWatchers || dumpHistory) {
Dianne Hackborn125dc532019-01-09 13:31:48 -08004969 continue;
4970 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004971 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
Hai Zhang93540ca2019-09-28 00:04:18 +00004972 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
4973 && uidState.opModes.indexOfKey(dumpOp) >= 0);
Philip P. Moltmannceffd592020-01-02 12:05:15 -08004974 boolean hasPackage = dumpPackage == null || dumpUid == mUidStates.keyAt(i);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004975 boolean hasMode = dumpMode < 0;
Hai Zhang93540ca2019-09-28 00:04:18 +00004976 if (!hasMode && opModes != null) {
4977 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
4978 if (opModes.valueAt(opi) == dumpMode) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004979 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004980 }
4981 }
4982 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004983 if (pkgOps != null) {
4984 for (int pkgi = 0;
Svet Ganov8455ba22019-01-02 13:05:56 -08004985 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
4986 pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004987 Ops ops = pkgOps.valueAt(pkgi);
4988 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
4989 hasOp = true;
4990 }
4991 if (!hasMode) {
4992 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
4993 if (ops.valueAt(opi).mode == dumpMode) {
4994 hasMode = true;
4995 }
4996 }
4997 }
4998 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
4999 hasPackage = true;
5000 }
5001 }
5002 }
5003 if (uidState.foregroundOps != null && !hasOp) {
5004 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
5005 hasOp = true;
5006 }
5007 }
5008 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005009 continue;
5010 }
5011 }
Svet Ganov2af57082015-07-30 08:44:20 -07005012
5013 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07005014 pw.print(" state=");
Svet Ganovaf189e32019-02-15 18:45:29 -08005015 pw.println(AppOpsManager.getUidStateName(uidState.state));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005016 if (uidState.state != uidState.pendingState) {
5017 pw.print(" pendingState=");
Svet Ganovaf189e32019-02-15 18:45:29 -08005018 pw.println(AppOpsManager.getUidStateName(uidState.pendingState));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005019 }
Hui Yu26969322019-08-21 14:56:35 -07005020 pw.print(" capability=");
5021 pw.println(uidState.capability);
5022 if (uidState.capability != uidState.pendingCapability) {
5023 pw.print(" pendingCapability=");
5024 pw.println(uidState.pendingCapability);
5025 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005026 if (uidState.pendingStateCommitTime != 0) {
5027 pw.print(" pendingStateCommitTime=");
Dianne Hackborn9fb93502018-06-18 12:29:44 -07005028 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005029 pw.println();
5030 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005031 if (uidState.foregroundOps != null && (dumpMode < 0
5032 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005033 pw.println(" foregroundOps:");
5034 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005035 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
5036 continue;
5037 }
5038 pw.print(" ");
5039 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
5040 pw.print(": ");
5041 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005042 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005043 pw.print(" hasForegroundWatchers=");
5044 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005045 }
Svet Ganovee438d42017-01-19 18:04:38 -08005046 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07005047
Hai Zhang93540ca2019-09-28 00:04:18 +00005048 if (opModes != null) {
5049 final int opModeCount = opModes.size();
5050 for (int j = 0; j < opModeCount; j++) {
5051 final int code = opModes.keyAt(j);
5052 final int mode = opModes.valueAt(j);
5053 if (dumpOp >= 0 && dumpOp != code) {
5054 continue;
5055 }
5056 if (dumpMode >= 0 && dumpMode != mode) {
5057 continue;
5058 }
5059 pw.print(" "); pw.print(AppOpsManager.opToName(code));
5060 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07005061 }
5062 }
5063
Svet Ganov2af57082015-07-30 08:44:20 -07005064 if (pkgOps == null) {
5065 continue;
5066 }
5067
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005068 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005069 final Ops ops = pkgOps.valueAt(pkgi);
5070 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
5071 continue;
5072 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005073 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005074 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005075 final Op op = ops.valueAt(j);
Svet Ganovaf189e32019-02-15 18:45:29 -08005076 final int opCode = op.op;
5077 if (dumpOp >= 0 && dumpOp != opCode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005078 continue;
5079 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005080 if (dumpMode >= 0 && dumpMode != op.mode) {
5081 continue;
5082 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005083 if (!printedPackage) {
5084 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
5085 printedPackage = true;
5086 }
Svet Ganovaf189e32019-02-15 18:45:29 -08005087 pw.print(" "); pw.print(AppOpsManager.opToName(opCode));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005088 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Svet Ganovaf189e32019-02-15 18:45:29 -08005089 final int switchOp = AppOpsManager.opToSwitch(opCode);
5090 if (switchOp != opCode) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005091 pw.print(" / switch ");
5092 pw.print(AppOpsManager.opToName(switchOp));
5093 final Op switchObj = ops.get(switchOp);
Svet Ganovaf189e32019-02-15 18:45:29 -08005094 int mode = switchObj != null ? switchObj.mode
5095 : AppOpsManager.opToDefaultMode(switchOp);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005096 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
5097 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005098 pw.println("): ");
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005099 dumpStatesLocked(pw, dumpFeatureId, dumpFilter, nowElapsed, op, now, sdf,
5100 date, " ");
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005101 }
5102 }
5103 }
Svet Ganovee438d42017-01-19 18:04:38 -08005104 if (needSep) {
5105 pw.println();
5106 }
5107
5108 final int userRestrictionCount = mOpUserRestrictions.size();
5109 for (int i = 0; i < userRestrictionCount; i++) {
5110 IBinder token = mOpUserRestrictions.keyAt(i);
5111 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Dianne Hackborn125dc532019-01-09 13:31:48 -08005112 boolean printedTokenHeader = false;
5113
Svet Ganovaf189e32019-02-15 18:45:29 -08005114 if (dumpMode >= 0 || dumpWatchers || dumpHistory) {
Dianne Hackborn125dc532019-01-09 13:31:48 -08005115 continue;
5116 }
Svet Ganovee438d42017-01-19 18:04:38 -08005117
5118 final int restrictionCount = restrictionState.perUserRestrictions != null
5119 ? restrictionState.perUserRestrictions.size() : 0;
Dianne Hackborn125dc532019-01-09 13:31:48 -08005120 if (restrictionCount > 0 && dumpPackage == null) {
5121 boolean printedOpsHeader = false;
Svet Ganovee438d42017-01-19 18:04:38 -08005122 for (int j = 0; j < restrictionCount; j++) {
5123 int userId = restrictionState.perUserRestrictions.keyAt(j);
5124 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
5125 if (restrictedOps == null) {
5126 continue;
5127 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08005128 if (dumpOp >= 0 && (dumpOp >= restrictedOps.length
5129 || !restrictedOps[dumpOp])) {
5130 continue;
5131 }
5132 if (!printedTokenHeader) {
5133 pw.println(" User restrictions for token " + token + ":");
5134 printedTokenHeader = true;
5135 }
5136 if (!printedOpsHeader) {
5137 pw.println(" Restricted ops:");
5138 printedOpsHeader = true;
5139 }
Svet Ganovee438d42017-01-19 18:04:38 -08005140 StringBuilder restrictedOpsValue = new StringBuilder();
5141 restrictedOpsValue.append("[");
5142 final int restrictedOpCount = restrictedOps.length;
5143 for (int k = 0; k < restrictedOpCount; k++) {
5144 if (restrictedOps[k]) {
5145 if (restrictedOpsValue.length() > 1) {
5146 restrictedOpsValue.append(", ");
5147 }
5148 restrictedOpsValue.append(AppOpsManager.opToName(k));
5149 }
5150 }
5151 restrictedOpsValue.append("]");
5152 pw.print(" "); pw.print("user: "); pw.print(userId);
5153 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
5154 }
5155 }
5156
5157 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
5158 ? restrictionState.perUserExcludedPackages.size() : 0;
Dianne Hackborn125dc532019-01-09 13:31:48 -08005159 if (excludedPackageCount > 0 && dumpOp < 0) {
5160 boolean printedPackagesHeader = false;
Svet Ganovee438d42017-01-19 18:04:38 -08005161 for (int j = 0; j < excludedPackageCount; j++) {
5162 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
5163 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
Dianne Hackborn125dc532019-01-09 13:31:48 -08005164 if (packageNames == null) {
5165 continue;
5166 }
5167 boolean hasPackage;
5168 if (dumpPackage != null) {
5169 hasPackage = false;
5170 for (String pkg : packageNames) {
5171 if (dumpPackage.equals(pkg)) {
5172 hasPackage = true;
5173 break;
5174 }
5175 }
5176 } else {
5177 hasPackage = true;
5178 }
5179 if (!hasPackage) {
5180 continue;
5181 }
5182 if (!printedTokenHeader) {
5183 pw.println(" User restrictions for token " + token + ":");
5184 printedTokenHeader = true;
5185 }
5186 if (!printedPackagesHeader) {
5187 pw.println(" Excluded packages:");
5188 printedPackagesHeader = true;
5189 }
Svet Ganovee438d42017-01-19 18:04:38 -08005190 pw.print(" "); pw.print("user: "); pw.print(userId);
5191 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
5192 }
5193 }
5194 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005195 }
Svet Ganov8455ba22019-01-02 13:05:56 -08005196
5197 // Must not hold the appops lock
Svet Ganovaf189e32019-02-15 18:45:29 -08005198 if (dumpHistory && !dumpWatchers) {
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005199 mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpFeatureId, dumpOp,
5200 dumpFilter);
Svet Ganovaf189e32019-02-15 18:45:29 -08005201 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005202 }
John Spurlock1af30c72014-03-10 08:33:35 -04005203
Jason Monk62062992014-05-06 09:55:28 -04005204 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005205 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04005206 checkSystemUid("setUserRestrictions");
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00005207 Objects.requireNonNull(restrictions);
5208 Objects.requireNonNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005209 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04005210 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07005211 if (restriction != null) {
5212 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
5213 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005214 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005215 }
5216 }
5217
5218 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08005219 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
5220 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005221 if (Binder.getCallingPid() != Process.myPid()) {
5222 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
5223 Binder.getCallingPid(), Binder.getCallingUid(), null);
5224 }
5225 if (userHandle != UserHandle.getCallingUserId()) {
5226 if (mContext.checkCallingOrSelfPermission(Manifest.permission
5227 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
5228 && mContext.checkCallingOrSelfPermission(Manifest.permission
5229 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
5230 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
5231 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04005232 }
5233 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005234 verifyIncomingOp(code);
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00005235 Objects.requireNonNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08005236 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005237 }
5238
5239 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08005240 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07005241 synchronized (AppOpsService.this) {
5242 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
5243
5244 if (restrictionState == null) {
5245 try {
5246 restrictionState = new ClientRestrictionState(token);
5247 } catch (RemoteException e) {
5248 return;
5249 }
5250 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08005251 }
Svet Ganov442ed572016-08-17 17:29:43 -07005252
5253 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005254 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07005255 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07005256 }
5257
5258 if (restrictionState.isDefault()) {
5259 mOpUserRestrictions.remove(token);
5260 restrictionState.destroy();
5261 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08005262 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04005263 }
5264
Svet Ganov3a95f832018-03-23 17:44:30 -07005265 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005266 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005267 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005268 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005269 if (callbacks == null) {
5270 return;
5271 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08005272 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005273 }
5274
Svet Ganov3a95f832018-03-23 17:44:30 -07005275 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04005276 }
5277
5278 @Override
5279 public void removeUser(int userHandle) throws RemoteException {
5280 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07005281 synchronized (AppOpsService.this) {
5282 final int tokenCount = mOpUserRestrictions.size();
5283 for (int i = tokenCount - 1; i >= 0; i--) {
5284 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
5285 opRestrictions.removeUser(userHandle);
5286 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07005287 removeUidsForUserLocked(userHandle);
5288 }
5289 }
5290
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005291 @Override
5292 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08005293 if (Binder.getCallingUid() != uid) {
5294 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
5295 != PackageManager.PERMISSION_GRANTED) {
5296 return false;
5297 }
5298 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005299 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005300 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005301 if (resolvedPackageName == null) {
5302 return false;
5303 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07005304 // TODO moltmann: Allow to check for feature op activeness
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005305 synchronized (AppOpsService.this) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08005306 Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false, false);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005307 if (pkgOps == null) {
5308 return false;
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005309 }
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005310
5311 Op op = pkgOps.get(code);
5312 if (op == null) {
5313 return false;
5314 }
5315
5316 return op.isRunning();
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005317 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005318 }
5319
Svet Ganov8455ba22019-01-02 13:05:56 -08005320 @Override
5321 public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
5322 long baseSnapshotInterval, int compressionStep) {
5323 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5324 "setHistoryParameters");
5325 // Must not hold the appops lock
5326 mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
5327 }
5328
5329 @Override
5330 public void offsetHistory(long offsetMillis) {
5331 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5332 "offsetHistory");
5333 // Must not hold the appops lock
5334 mHistoricalRegistry.offsetHistory(offsetMillis);
5335 }
5336
5337 @Override
5338 public void addHistoricalOps(HistoricalOps ops) {
5339 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5340 "addHistoricalOps");
5341 // Must not hold the appops lock
5342 mHistoricalRegistry.addHistoricalOps(ops);
5343 }
5344
5345 @Override
5346 public void resetHistoryParameters() {
5347 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5348 "resetHistoryParameters");
5349 // Must not hold the appops lock
5350 mHistoricalRegistry.resetHistoryParameters();
5351 }
5352
5353 @Override
5354 public void clearHistory() {
5355 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5356 "clearHistory");
5357 // Must not hold the appops lock
5358 mHistoricalRegistry.clearHistory();
5359 }
5360
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07005361 private void removeUidsForUserLocked(int userHandle) {
5362 for (int i = mUidStates.size() - 1; i >= 0; --i) {
5363 final int uid = mUidStates.keyAt(i);
5364 if (UserHandle.getUserId(uid) == userHandle) {
5365 mUidStates.removeAt(i);
5366 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005367 }
5368 }
5369
Jason Monk62062992014-05-06 09:55:28 -04005370 private void checkSystemUid(String function) {
5371 int uid = Binder.getCallingUid();
5372 if (uid != Process.SYSTEM_UID) {
5373 throw new SecurityException(function + " must by called by the system");
5374 }
5375 }
5376
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00005377 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08005378 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00005379 return "root";
5380 } else if (uid == Process.SHELL_UID) {
5381 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08005382 } else if (uid == Process.MEDIA_UID) {
5383 return "media";
5384 } else if (uid == Process.AUDIOSERVER_UID) {
5385 return "audioserver";
5386 } else if (uid == Process.CAMERASERVER_UID) {
5387 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00005388 } else if (uid == Process.SYSTEM_UID && packageName == null) {
5389 return "android";
5390 }
5391 return packageName;
5392 }
5393
Svet Ganov82f09bc2018-01-12 22:08:40 -08005394 private static int resolveUid(String packageName) {
5395 if (packageName == null) {
5396 return -1;
5397 }
5398 switch (packageName) {
5399 case "root":
5400 return Process.ROOT_UID;
5401 case "shell":
5402 return Process.SHELL_UID;
5403 case "media":
5404 return Process.MEDIA_UID;
5405 case "audioserver":
5406 return Process.AUDIOSERVER_UID;
5407 case "cameraserver":
5408 return Process.CAMERASERVER_UID;
5409 }
5410 return -1;
5411 }
5412
Svet Ganov2af57082015-07-30 08:44:20 -07005413 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07005414 String[] packageNames = null;
Philip P. Moltmann159d98b2018-12-20 08:30:53 -08005415
5416 // Very early during boot the package manager is not yet or not yet fully started. At this
5417 // time there are no packages yet.
5418 if (AppGlobals.getPackageManager() != null) {
5419 try {
5420 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
5421 } catch (RemoteException e) {
5422 /* ignore - local call */
5423 }
Svet Ganov2af57082015-07-30 08:44:20 -07005424 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07005425 if (packageNames == null) {
5426 return EmptyArray.STRING;
5427 }
5428 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07005429 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005430
5431 private final class ClientRestrictionState implements DeathRecipient {
5432 private final IBinder token;
5433 SparseArray<boolean[]> perUserRestrictions;
5434 SparseArray<String[]> perUserExcludedPackages;
5435
5436 public ClientRestrictionState(IBinder token)
5437 throws RemoteException {
5438 token.linkToDeath(this, 0);
5439 this.token = token;
5440 }
5441
5442 public boolean setRestriction(int code, boolean restricted,
5443 String[] excludedPackages, int userId) {
5444 boolean changed = false;
5445
5446 if (perUserRestrictions == null && restricted) {
5447 perUserRestrictions = new SparseArray<>();
5448 }
5449
Philip P. Moltmanne683f192017-06-23 14:05:04 -07005450 int[] users;
5451 if (userId == UserHandle.USER_ALL) {
5452 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005453
Philip P. Moltmanne683f192017-06-23 14:05:04 -07005454 users = new int[liveUsers.size()];
5455 for (int i = 0; i < liveUsers.size(); i++) {
5456 users[i] = liveUsers.get(i).id;
5457 }
5458 } else {
5459 users = new int[]{userId};
5460 }
5461
5462 if (perUserRestrictions != null) {
5463 int numUsers = users.length;
5464
5465 for (int i = 0; i < numUsers; i++) {
5466 int thisUserId = users[i];
5467
5468 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
5469 if (userRestrictions == null && restricted) {
5470 userRestrictions = new boolean[AppOpsManager._NUM_OP];
5471 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005472 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07005473 if (userRestrictions != null && userRestrictions[code] != restricted) {
5474 userRestrictions[code] = restricted;
5475 if (!restricted && isDefault(userRestrictions)) {
5476 perUserRestrictions.remove(thisUserId);
5477 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005478 }
5479 changed = true;
5480 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07005481
5482 if (userRestrictions != null) {
5483 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
5484 if (perUserExcludedPackages == null && !noExcludedPackages) {
5485 perUserExcludedPackages = new SparseArray<>();
5486 }
5487 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
5488 perUserExcludedPackages.get(thisUserId))) {
5489 if (noExcludedPackages) {
5490 perUserExcludedPackages.remove(thisUserId);
5491 if (perUserExcludedPackages.size() <= 0) {
5492 perUserExcludedPackages = null;
5493 }
5494 } else {
5495 perUserExcludedPackages.put(thisUserId, excludedPackages);
5496 }
5497 changed = true;
5498 }
5499 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005500 }
5501 }
5502
5503 return changed;
5504 }
5505
5506 public boolean hasRestriction(int restriction, String packageName, int userId) {
5507 if (perUserRestrictions == null) {
5508 return false;
5509 }
5510 boolean[] restrictions = perUserRestrictions.get(userId);
5511 if (restrictions == null) {
5512 return false;
5513 }
5514 if (!restrictions[restriction]) {
5515 return false;
5516 }
5517 if (perUserExcludedPackages == null) {
5518 return true;
5519 }
5520 String[] perUserExclusions = perUserExcludedPackages.get(userId);
5521 if (perUserExclusions == null) {
5522 return true;
5523 }
5524 return !ArrayUtils.contains(perUserExclusions, packageName);
5525 }
5526
5527 public void removeUser(int userId) {
5528 if (perUserExcludedPackages != null) {
5529 perUserExcludedPackages.remove(userId);
5530 if (perUserExcludedPackages.size() <= 0) {
5531 perUserExcludedPackages = null;
5532 }
5533 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07005534 if (perUserRestrictions != null) {
5535 perUserRestrictions.remove(userId);
5536 if (perUserRestrictions.size() <= 0) {
5537 perUserRestrictions = null;
5538 }
5539 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005540 }
5541
5542 public boolean isDefault() {
5543 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
5544 }
5545
5546 @Override
5547 public void binderDied() {
5548 synchronized (AppOpsService.this) {
5549 mOpUserRestrictions.remove(token);
5550 if (perUserRestrictions == null) {
5551 return;
5552 }
5553 final int userCount = perUserRestrictions.size();
5554 for (int i = 0; i < userCount; i++) {
5555 final boolean[] restrictions = perUserRestrictions.valueAt(i);
5556 final int restrictionCount = restrictions.length;
5557 for (int j = 0; j < restrictionCount; j++) {
5558 if (restrictions[j]) {
5559 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07005560 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005561 }
5562 }
5563 }
5564 destroy();
5565 }
5566 }
5567
5568 public void destroy() {
5569 token.unlinkToDeath(this, 0);
5570 }
5571
5572 private boolean isDefault(boolean[] array) {
5573 if (ArrayUtils.isEmpty(array)) {
5574 return true;
5575 }
5576 for (boolean value : array) {
5577 if (value) {
5578 return false;
5579 }
5580 }
5581 return true;
5582 }
5583 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07005584
5585 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
5586 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
5587 synchronized (AppOpsService.this) {
5588 mProfileOwners = owners;
5589 }
5590 }
Hui Yu88910de2019-12-16 14:35:27 -08005591
5592 @Override
5593 public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames,
5594 boolean visible) {
5595 AppOpsService.this.updateAppWidgetVisibility(uidPackageNames, visible);
5596 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07005597 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005598}