blob: 63e01e034d7ec9225f6304c9eaa6217c5eafbb8d [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. Moltmann7641cd02020-03-11 14:42:43 -070022import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -080023import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
Philip P. Moltmann4aacd712020-01-03 12:32:20 -080024import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
25import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
26import static android.app.AppOpsManager.FILTER_BY_UID;
27import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
Philip P. Moltmanne565c7b2020-01-28 13:15:52 -080028import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
29import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
30import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
Hui Yu88910de2019-12-16 14:35:27 -080031import static android.app.AppOpsManager.MODE_ALLOWED;
Hui Yubb866ad2020-03-04 12:33:40 -080032import static android.app.AppOpsManager.MODE_FOREGROUND;
33import static android.app.AppOpsManager.MODE_IGNORED;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -080034import static android.app.AppOpsManager.NoteOpEvent;
Suprabh Shukla7e017922019-08-05 17:13:23 -070035import static android.app.AppOpsManager.OP_CAMERA;
Svet Ganovaf189e32019-02-15 18:45:29 -080036import static android.app.AppOpsManager.OP_FLAGS_ALL;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -080037import static android.app.AppOpsManager.OP_FLAG_SELF;
Stanislav Zholnin90516b92020-01-20 14:03:06 +000038import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
Svet Ganov8455ba22019-01-02 13:05:56 -080039import static android.app.AppOpsManager.OP_NONE;
Philip P. Moltmanndde07852019-01-25 16:42:36 -080040import static android.app.AppOpsManager.OP_PLAY_AUDIO;
Suprabh Shukla7e017922019-08-05 17:13:23 -070041import static android.app.AppOpsManager.OP_RECORD_AUDIO;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080042import static android.app.AppOpsManager.OpEventProxyInfo;
Philip P. Moltmannad787aa2020-03-10 09:49:22 -070043import static android.app.AppOpsManager.RestrictionBypass;
Stanislav Zholnin4c323852020-03-04 18:03:24 +000044import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
Muhammad Qureshi317061a2020-03-02 13:15:51 -080045import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
46import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
Hai Zhang2b98fb32018-09-21 15:18:46 -070047import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
48import static android.app.AppOpsManager.UID_STATE_CACHED;
49import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
50import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
Svet Ganovaf189e32019-02-15 18:45:29 -080051import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
Hai Zhang2b98fb32018-09-21 15:18:46 -070052import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
53import static android.app.AppOpsManager.UID_STATE_TOP;
Philip P. Moltmann584c23a2020-01-24 14:21:12 -080054import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070055import static android.app.AppOpsManager._NUM_OP;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -080056import static android.app.AppOpsManager.extractFlagsFromKey;
57import static android.app.AppOpsManager.extractUidStateFromKey;
58import static android.app.AppOpsManager.makeKey;
Eugene Suslae4ee2c22018-11-05 12:23:30 -080059import static android.app.AppOpsManager.modeToName;
Philip P. Moltmannad787aa2020-03-10 09:49:22 -070060import static android.app.AppOpsManager.opAllowSystemBypassRestriction;
Eugene Suslae4ee2c22018-11-05 12:23:30 -080061import static android.app.AppOpsManager.opToName;
Stanislav Zholnin90516b92020-01-20 14:03:06 +000062import static android.app.AppOpsManager.opToPublicName;
Svet Ganovaf189e32019-02-15 18:45:29 -080063import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080064import static android.content.Intent.ACTION_PACKAGE_REMOVED;
65import static android.content.Intent.EXTRA_REPLACING;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070066import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
Philip P. Moltmann87fd8bc2020-02-13 13:16:13 -080067import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
Hai Zhang2b98fb32018-09-21 15:18:46 -070068
Hui Yu77fd8192020-03-27 00:22:57 -070069import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
70import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
71import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION;
72import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
73import static com.android.server.am.OomAdjuster.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -080074import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
75
Philip P. Moltmann463979e2020-01-24 14:41:22 -080076import static java.lang.Long.max;
77
Philip P. Moltmanne683f192017-06-23 14:05:04 -070078import android.Manifest;
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -080079import android.annotation.IntRange;
Svet Ganovad0a49b2018-10-29 10:07:08 -070080import android.annotation.NonNull;
81import android.annotation.Nullable;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070082import android.app.ActivityManager;
Nate Myren697650b2020-01-23 13:25:06 -080083import android.app.ActivityManagerInternal;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070084import android.app.AppGlobals;
85import android.app.AppOpsManager;
Philip P. Moltmann5ab15b02020-03-13 15:44:51 -070086import android.app.AppOpsManager.AttributedOpEntry;
Svet Ganov8455ba22019-01-02 13:05:56 -080087import android.app.AppOpsManager.HistoricalOps;
Svet Ganovaf189e32019-02-15 18:45:29 -080088import android.app.AppOpsManager.Mode;
89import android.app.AppOpsManager.OpEntry;
90import android.app.AppOpsManager.OpFlags;
Dianne Hackbornd5254412018-05-11 18:02:58 -070091import android.app.AppOpsManagerInternal;
Svet Ganovd873ae62018-06-25 16:39:23 -070092import android.app.AppOpsManagerInternal.CheckOpsDelegate;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -070093import android.app.AsyncNotedAppOp;
Stanislav Zholnin90516b92020-01-20 14:03:06 +000094import android.app.RuntimeAppOpAccessMessage;
95import android.app.SyncNotedAppOp;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080096import android.content.BroadcastReceiver;
Dianne Hackborn65a4f252018-05-08 17:30:48 -070097import android.content.ContentResolver;
Philip P. Moltmanne683f192017-06-23 14:05:04 -070098import android.content.Context;
Suprabh Shukla3017fe42018-11-08 19:00:01 -080099import android.content.Intent;
100import android.content.IntentFilter;
Stanislav Zholnin90516b92020-01-20 14:03:06 +0000101import android.content.pm.PackageInfo;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700102import android.content.pm.PackageManager;
103import android.content.pm.PackageManagerInternal;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700104import android.content.pm.PermissionInfo;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700105import android.content.pm.UserInfo;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800106import android.content.pm.parsing.component.ParsedAttribution;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700107import android.database.ContentObserver;
Yin-Chia Yeh51d85162019-08-06 15:31:39 -0700108import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700109import android.net.Uri;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700110import android.os.AsyncTask;
111import android.os.Binder;
Hai Zhang23d30a22020-02-04 11:06:31 -0800112import android.os.Build;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700113import android.os.Bundle;
114import android.os.Handler;
115import android.os.IBinder;
116import android.os.Process;
Svet Ganov8455ba22019-01-02 13:05:56 -0800117import android.os.RemoteCallback;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700118import android.os.RemoteCallbackList;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700119import android.os.RemoteException;
120import android.os.ResultReceiver;
121import android.os.ServiceManager;
122import android.os.ShellCallback;
123import android.os.ShellCommand;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700124import android.os.SystemClock;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700125import android.os.UserHandle;
126import android.os.UserManager;
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700127import android.os.storage.StorageManager;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700128import android.os.storage.StorageManagerInternal;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700129import android.provider.Settings;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700130import android.util.ArrayMap;
131import android.util.ArraySet;
132import android.util.AtomicFile;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700133import android.util.KeyValueListParser;
Svet Ganovaf189e32019-02-15 18:45:29 -0800134import android.util.LongSparseArray;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700135import android.util.Pair;
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800136import android.util.Pools.SimplePool;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700137import android.util.Slog;
138import android.util.SparseArray;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700139import android.util.SparseBooleanArray;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700140import android.util.SparseIntArray;
141import android.util.TimeUtils;
142import android.util.Xml;
143
Todd Kennedy556efba2018-11-15 07:43:55 -0800144import com.android.internal.annotations.GuardedBy;
David Cheung2ead9662020-02-19 16:11:06 -0800145import com.android.internal.annotations.Immutable;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700146import com.android.internal.annotations.VisibleForTesting;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800147import com.android.internal.app.IAppOpsActiveCallback;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700148import com.android.internal.app.IAppOpsAsyncNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700149import com.android.internal.app.IAppOpsCallback;
Svet Ganovb3d2ae22018-12-17 22:06:15 -0800150import com.android.internal.app.IAppOpsNotedCallback;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700151import com.android.internal.app.IAppOpsService;
Adam Bookatz182862e2020-04-27 21:58:22 -0700152import com.android.internal.app.IAppOpsStartedCallback;
Stanislav Zholnin90516b92020-01-20 14:03:06 +0000153import com.android.internal.app.MessageSamplingConfig;
Philip P. Moltmanne683f192017-06-23 14:05:04 -0700154import com.android.internal.os.Zygote;
155import com.android.internal.util.ArrayUtils;
156import com.android.internal.util.DumpUtils;
157import com.android.internal.util.FastXmlSerializer;
158import com.android.internal.util.Preconditions;
159import com.android.internal.util.XmlUtils;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -0800160import com.android.internal.util.function.pooled.PooledLambda;
Svet Ganov8455ba22019-01-02 13:05:56 -0800161import com.android.server.LocalServices;
162import com.android.server.LockGuard;
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800163import com.android.server.SystemServerInitThreadPool;
David Cheung2ead9662020-02-19 16:11:06 -0800164import com.android.server.SystemServiceManager;
Stanislav Zholnin90516b92020-01-20 14:03:06 +0000165import com.android.server.pm.PackageList;
Winsonf00c7552020-01-28 12:52:01 -0800166import com.android.server.pm.parsing.pkg.AndroidPackage;
Philip P. Moltmanndde07852019-01-25 16:42:36 -0800167
Philip P. Moltmann02cd91b2019-11-05 14:29:52 -0800168import libcore.util.EmptyArray;
169
David Cheung2ead9662020-02-19 16:11:06 -0800170import org.json.JSONException;
171import org.json.JSONObject;
Philip P. Moltmann02cd91b2019-11-05 14:29:52 -0800172import org.xmlpull.v1.XmlPullParser;
173import org.xmlpull.v1.XmlPullParserException;
174import org.xmlpull.v1.XmlSerializer;
175
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800176import java.io.File;
177import java.io.FileDescriptor;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800178import java.io.FileInputStream;
179import java.io.FileNotFoundException;
180import java.io.FileOutputStream;
David Cheung2ead9662020-02-19 16:11:06 -0800181import java.io.FileWriter;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800182import java.io.IOException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800183import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100184import java.nio.charset.StandardCharsets;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700185import java.text.SimpleDateFormat;
Stanislav Zholnin90516b92020-01-20 14:03:06 +0000186import java.time.Instant;
187import java.time.temporal.ChronoUnit;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800188import java.util.ArrayList;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700189import java.util.Arrays;
Svetoslav215b44a2015-08-04 19:03:40 -0700190import java.util.Collections;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700191import java.util.Date;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800192import java.util.HashMap;
Dianne Hackbornc2293022013-02-06 23:14:49 -0800193import java.util.Iterator;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800194import java.util.List;
Dianne Hackborn607b4142013-08-02 18:10:10 -0700195import java.util.Map;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700196import java.util.Objects;
David Cheung2ead9662020-02-19 16:11:06 -0800197import java.util.Scanner;
Stanislav Zholnin90516b92020-01-20 14:03:06 +0000198import java.util.concurrent.ThreadLocalRandom;
199import java.util.function.Consumer;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800200
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800201public class AppOpsService extends IAppOpsService.Stub {
202 static final String TAG = "AppOps";
Dianne Hackborn35654b62013-01-14 17:38:02 -0800203 static final boolean DEBUG = false;
204
David Cheung2ead9662020-02-19 16:11:06 -0800205 /**
206 * Used for data access validation collection, we wish to only log a specific access once
207 */
208 private final ArraySet<NoteOpTrace> mNoteOpCallerStacktraces = new ArraySet<>();
209
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700210 private static final int NO_VERSION = -1;
211 /** Increment by one every time and add the corresponding upgrade logic in
212 * {@link #upgradeLocked(int)} below. The first version was 1 */
213 private static final int CURRENT_VERSION = 1;
214
Dianne Hackborn35654b62013-01-14 17:38:02 -0800215 // Write at most every 30 minutes.
216 static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800217
Svet Ganov3a95f832018-03-23 17:44:30 -0700218 // Constant meaning that any UID should be matched when dispatching callbacks
219 private static final int UID_ANY = -2;
220
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700221 // Map from process states to the uid states we track.
222 private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
223 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
224 UID_STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
225 UID_STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
Amith Yamasanif235d0b2019-03-20 22:49:43 -0700226 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_TOP
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700227 UID_STATE_FOREGROUND_SERVICE, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
228 UID_STATE_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
Hui Yu26969322019-08-21 14:56:35 -0700229 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700230 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
231 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
232 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_BACKUP
233 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_SERVICE
234 UID_STATE_BACKGROUND, // ActivityManager.PROCESS_STATE_RECEIVER
235 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
236 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
237 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_HOME
238 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
239 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
240 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
241 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_RECENT
242 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
243 UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
244 };
245
Suprabh Shukla7e017922019-08-05 17:13:23 -0700246 private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
247 OP_PLAY_AUDIO,
248 OP_RECORD_AUDIO,
249 OP_CAMERA,
250 };
251
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700252 private static final int MAX_UNFORWARED_OPS = 10;
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800253 private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
Stanislav Zholnin4c323852020-03-04 18:03:24 +0000254 private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700255
Hui Yu0620a332020-01-27 14:59:07 -0800256 //TODO: remove this when development is done.
Hui Yue9b40ba2020-03-05 17:16:27 -0800257 private static final int DEBUG_FGS_ALLOW_WHILE_IN_USE = 0;
258 private static final int DEBUG_FGS_ENFORCE_TYPE = 1;
259
Hui Yu0620a332020-01-27 14:59:07 -0800260
Philip P. Moltmannfe2fc3a2020-02-05 16:59:39 -0800261 final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800262 final AtomicFile mFile;
David Cheung2ead9662020-02-19 16:11:06 -0800263 private final @Nullable File mNoteOpCallerStacktracesFile;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800264 final Handler mHandler;
265
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800266 /** Pool for {@link OpEventProxyInfoPool} to avoid to constantly reallocate new objects */
267 @GuardedBy("this")
268 private final OpEventProxyInfoPool mOpEventProxyInfoPool = new OpEventProxyInfoPool();
269
270 /** Pool for {@link InProgressStartOpEventPool} to avoid to constantly reallocate new objects */
271 @GuardedBy("this")
272 private final InProgressStartOpEventPool mInProgressStartOpEventPool =
273 new InProgressStartOpEventPool();
274
Dianne Hackbornd5254412018-05-11 18:02:58 -0700275 private final AppOpsManagerInternalImpl mAppOpsManagerInternal
276 = new AppOpsManagerInternalImpl();
277
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700278 /**
Philip P. Moltmannda554e42019-12-20 11:21:02 -0800279 * Registered callbacks, called from {@link #collectAsyncNotedOp}.
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700280 *
281 * <p>(package name, uid) -> callbacks
282 *
283 * @see #getAsyncNotedOpsKey(String, int)
284 */
285 @GuardedBy("this")
286 private final ArrayMap<Pair<String, Integer>, RemoteCallbackList<IAppOpsAsyncNotedCallback>>
287 mAsyncOpWatchers = new ArrayMap<>();
288
289 /**
Philip P. Moltmannda554e42019-12-20 11:21:02 -0800290 * Async note-ops collected from {@link #collectAsyncNotedOp} that have not been delivered to a
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -0700291 * callback yet.
292 *
293 * <p>(package name, uid) -> list&lt;ops&gt;
294 *
295 * @see #getAsyncNotedOpsKey(String, int)
296 */
297 @GuardedBy("this")
298 private final ArrayMap<Pair<String, Integer>, ArrayList<AsyncNotedAppOp>>
299 mUnforwardedAsyncNotedOps = new ArrayMap<>();
300
David Cheung2ead9662020-02-19 16:11:06 -0800301 boolean mWriteNoteOpsScheduled;
302
Dianne Hackborn35654b62013-01-14 17:38:02 -0800303 boolean mWriteScheduled;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800304 boolean mFastWriteScheduled;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800305 final Runnable mWriteRunner = new Runnable() {
306 public void run() {
307 synchronized (AppOpsService.this) {
308 mWriteScheduled = false;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -0800309 mFastWriteScheduled = false;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800310 AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
311 @Override protected Void doInBackground(Void... params) {
312 writeState();
313 return null;
314 }
315 };
316 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
317 }
318 }
319 };
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800320
Eugene Susla463d5922019-07-17 18:14:15 -0700321 @GuardedBy("this")
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700322 @VisibleForTesting
323 final SparseArray<UidState> mUidStates = new SparseArray<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800324
Svet Ganov47641072019-06-06 12:57:12 -0700325 final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
Svet Ganov8455ba22019-01-02 13:05:56 -0800326
Dianne Hackborn9fb93502018-06-18 12:29:44 -0700327 long mLastRealtime;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700328
Ruben Brunk29931bc2016-03-11 00:24:26 -0800329 /*
330 * These are app op restrictions imposed per user from various parties.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800331 */
Svetoslav Ganova8bbd762016-05-13 17:08:16 -0700332 private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
Jason Monk62062992014-05-06 09:55:28 -0400333
Dianne Hackbornd5254412018-05-11 18:02:58 -0700334 SparseIntArray mProfileOwners;
335
Todd Kennedy556efba2018-11-15 07:43:55 -0800336 @GuardedBy("this")
Svet Ganovd873ae62018-06-25 16:39:23 -0700337 private CheckOpsDelegate mCheckOpsDelegate;
338
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -0800339 /**
340 * Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never
341 * changed
342 */
343 private final SparseArray<int[]> mSwitchedOps = new SparseArray<>();
Hai Zhange53e4c52019-10-08 18:57:01 -0700344
Hui Yu88910de2019-12-16 14:35:27 -0800345 private ActivityManagerInternal mActivityManagerInternal;
346
Stanislav Zholnin90516b92020-01-20 14:03:06 +0000347 /** Package sampled for message collection in the current session */
348 @GuardedBy("this")
349 private String mSampledPackage = null;
350
351 /** Appop sampled for message collection in the current session */
352 @GuardedBy("this")
353 private int mSampledAppOpCode = OP_NONE;
354
355 /** Maximum distance for appop to be considered for message collection in the current session */
356 @GuardedBy("this")
357 private int mAcceptableLeftDistance = 0;
358
359 /** Number of messages collected for sampled package and appop in the current session */
360 @GuardedBy("this")
361 private float mMessagesCollectedCount;
362
363 /** List of rarely used packages priorities for message collection */
364 @GuardedBy("this")
365 private ArraySet<String> mRarelyUsedPackages = new ArraySet<>();
366
367 /** Sampling strategy used for current session */
368 @GuardedBy("this")
369 @AppOpsManager.SamplingStrategy
370 private int mSamplingStrategy;
371
372 /** Last runtime permission access message collected and ready for reporting */
373 @GuardedBy("this")
374 private RuntimeAppOpAccessMessage mCollectedRuntimePermissionMessage;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700375 /**
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800376 * An unsynchronized pool of {@link OpEventProxyInfo} objects.
377 */
378 private class OpEventProxyInfoPool extends SimplePool<OpEventProxyInfo> {
379 OpEventProxyInfoPool() {
380 super(MAX_UNUSED_POOLED_OBJECTS);
381 }
382
383 OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800384 @Nullable String attributionTag) {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800385 OpEventProxyInfo recycled = acquire();
386 if (recycled != null) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800387 recycled.reinit(uid, packageName, attributionTag);
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800388 return recycled;
389 }
390
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800391 return new OpEventProxyInfo(uid, packageName, attributionTag);
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800392 }
393 }
394
395 /**
396 * An unsynchronized pool of {@link InProgressStartOpEvent} objects.
397 */
398 private class InProgressStartOpEventPool extends SimplePool<InProgressStartOpEvent> {
399 InProgressStartOpEventPool() {
400 super(MAX_UNUSED_POOLED_OBJECTS);
401 }
402
403 InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
404 @NonNull Runnable onDeath, int uidState) throws RemoteException {
405 InProgressStartOpEvent recycled = acquire();
406 if (recycled != null) {
407 recycled.reinit(startTime, elapsedTime, clientId, onDeath, uidState);
408 return recycled;
409 }
410
411 return new InProgressStartOpEvent(startTime, elapsedTime, clientId, onDeath, uidState);
412 }
413 }
414
415 /**
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700416 * All times are in milliseconds. These constants are kept synchronized with the system
417 * global Settings. Any access to this class or its fields should be done while
418 * holding the AppOpsService lock.
419 */
Amith Yamasani23d4cd72019-04-10 17:57:00 -0700420 @VisibleForTesting
421 final class Constants extends ContentObserver {
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700422
423 /**
Dianne Hackborne93ab412018-05-14 17:52:30 -0700424 * How long we want for a drop in uid state from top to settle before applying it.
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700425 * @see Settings.Global#APP_OPS_CONSTANTS
Philip P. Moltmanne565c7b2020-01-28 13:15:52 -0800426 * @see AppOpsManager#KEY_TOP_STATE_SETTLE_TIME
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700427 */
Dianne Hackborne93ab412018-05-14 17:52:30 -0700428 public long TOP_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700429
Dianne Hackborne93ab412018-05-14 17:52:30 -0700430 /**
431 * How long we want for a drop in uid state from foreground to settle before applying it.
432 * @see Settings.Global#APP_OPS_CONSTANTS
Philip P. Moltmanne565c7b2020-01-28 13:15:52 -0800433 * @see AppOpsManager#KEY_FG_SERVICE_STATE_SETTLE_TIME
Dianne Hackborne93ab412018-05-14 17:52:30 -0700434 */
435 public long FG_SERVICE_STATE_SETTLE_TIME;
436
437 /**
438 * How long we want for a drop in uid state from background to settle before applying it.
439 * @see Settings.Global#APP_OPS_CONSTANTS
Philip P. Moltmanne565c7b2020-01-28 13:15:52 -0800440 * @see AppOpsManager#KEY_BG_STATE_SETTLE_TIME
Dianne Hackborne93ab412018-05-14 17:52:30 -0700441 */
442 public long BG_STATE_SETTLE_TIME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700443
444 private final KeyValueListParser mParser = new KeyValueListParser(',');
445 private ContentResolver mResolver;
446
447 public Constants(Handler handler) {
448 super(handler);
449 updateConstants();
450 }
451
452 public void startMonitoring(ContentResolver resolver) {
453 mResolver = resolver;
454 mResolver.registerContentObserver(
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700455 Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700456 false, this);
457 updateConstants();
458 }
459
460 @Override
461 public void onChange(boolean selfChange, Uri uri) {
462 updateConstants();
463 }
464
465 private void updateConstants() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700466 String value = mResolver != null ? Settings.Global.getString(mResolver,
467 Settings.Global.APP_OPS_CONSTANTS) : "";
468
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700469 synchronized (AppOpsService.this) {
470 try {
Dianne Hackborn45c79b02018-05-11 09:46:13 -0700471 mParser.setString(value);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700472 } catch (IllegalArgumentException e) {
473 // Failed to parse the settings string, log this and move on
474 // with defaults.
475 Slog.e(TAG, "Bad app ops settings", e);
476 }
Dianne Hackborne93ab412018-05-14 17:52:30 -0700477 TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
Philip P. Moltmann88583dd2020-02-12 16:55:32 -0800478 KEY_TOP_STATE_SETTLE_TIME, 5 * 1000L);
Dianne Hackborne93ab412018-05-14 17:52:30 -0700479 FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
Philip P. Moltmann88583dd2020-02-12 16:55:32 -0800480 KEY_FG_SERVICE_STATE_SETTLE_TIME, 5 * 1000L);
Dianne Hackborne93ab412018-05-14 17:52:30 -0700481 BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
482 KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700483 }
484 }
485
486 void dump(PrintWriter pw) {
487 pw.println(" Settings:");
488
Dianne Hackborne93ab412018-05-14 17:52:30 -0700489 pw.print(" "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
490 TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700491 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700492 pw.print(" "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
493 TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
Dianne Hackbornb94d82f2018-05-16 17:03:01 -0700494 pw.println();
Dianne Hackborne93ab412018-05-14 17:52:30 -0700495 pw.print(" "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
496 TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700497 pw.println();
498 }
499 }
500
Amith Yamasani23d4cd72019-04-10 17:57:00 -0700501 @VisibleForTesting
502 final Constants mConstants;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700503
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -0700504 @VisibleForTesting
Hui Yu88910de2019-12-16 14:35:27 -0800505 final class UidState {
Svet Ganov2af57082015-07-30 08:44:20 -0700506 public final int uid;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700507
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700508 public int state = UID_STATE_CACHED;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700509 public int pendingState = UID_STATE_CACHED;
510 public long pendingStateCommitTime;
Hui Yu26969322019-08-21 14:56:35 -0700511 public int capability;
512 public int pendingCapability;
Hui Yu88910de2019-12-16 14:35:27 -0800513 public boolean appWidgetVisible;
514 public boolean pendingAppWidgetVisible;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700515
Svet Ganov2af57082015-07-30 08:44:20 -0700516 public ArrayMap<String, Ops> pkgOps;
Hai Zhang93540ca2019-09-28 00:04:18 +0000517 public SparseIntArray opModes;
Svet Ganov2af57082015-07-30 08:44:20 -0700518
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700519 // true indicates there is an interested observer, false there isn't but it has such an op
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700520 public SparseBooleanArray foregroundOps;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700521 public boolean hasForegroundWatchers;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700522
Hui Yu88910de2019-12-16 14:35:27 -0800523 public long lastTimeShowDebugToast;
524
Svet Ganov2af57082015-07-30 08:44:20 -0700525 public UidState(int uid) {
526 this.uid = uid;
527 }
528
529 public void clear() {
530 pkgOps = null;
531 opModes = null;
532 }
533
534 public boolean isDefault() {
535 return (pkgOps == null || pkgOps.isEmpty())
Svet Ganovaf189e32019-02-15 18:45:29 -0800536 && (opModes == null || opModes.size() <= 0)
537 && (state == UID_STATE_CACHED
538 && (pendingState == UID_STATE_CACHED));
Svet Ganov2af57082015-07-30 08:44:20 -0700539 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700540
Svet Ganovaf189e32019-02-15 18:45:29 -0800541 int evalMode(int op, int mode) {
Hui Yubb866ad2020-03-04 12:33:40 -0800542 if (mode == MODE_FOREGROUND) {
Hui Yu88910de2019-12-16 14:35:27 -0800543 if (appWidgetVisible) {
544 return MODE_ALLOWED;
545 } else if (state <= UID_STATE_TOP) {
Hui Yubb866ad2020-03-04 12:33:40 -0800546 // process is in TOP.
547 return MODE_ALLOWED;
Hui Yu26969322019-08-21 14:56:35 -0700548 } else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) {
549 // process is in foreground, check its capability.
550 switch (op) {
551 case AppOpsManager.OP_FINE_LOCATION:
552 case AppOpsManager.OP_COARSE_LOCATION:
553 case AppOpsManager.OP_MONITOR_LOCATION:
554 case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
Hui Yu88910de2019-12-16 14:35:27 -0800555 if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
Hui Yubb866ad2020-03-04 12:33:40 -0800556 return MODE_ALLOWED;
Hui Yu0620a332020-01-27 14:59:07 -0800557 } else if ((capability
Hui Yu77fd8192020-03-27 00:22:57 -0700558 & DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
Hui Yu0620a332020-01-27 14:59:07 -0800559 // The FGS has the location capability, but due to FGS BG start
560 // restriction it lost the capability, use temp location capability
561 // to mark this case.
Hui Yue9b40ba2020-03-05 17:16:27 -0800562 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
Hui Yubb866ad2020-03-04 12:33:40 -0800563 return MODE_IGNORED;
Hui Yu0620a332020-01-27 14:59:07 -0800564 } else {
Hui Yubb866ad2020-03-04 12:33:40 -0800565 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800566 }
Hui Yu85679b42020-01-15 15:52:08 -0800567 case OP_CAMERA:
Hui Yu88910de2019-12-16 14:35:27 -0800568 if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
Hui Yubb866ad2020-03-04 12:33:40 -0800569 return MODE_ALLOWED;
Hui Yu77fd8192020-03-27 00:22:57 -0700570 } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q)
Hui Yue9b40ba2020-03-05 17:16:27 -0800571 != 0) {
Hui Yue9b40ba2020-03-05 17:16:27 -0800572 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
573 return MODE_ALLOWED;
Hui Yu77fd8192020-03-27 00:22:57 -0700574 } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA)
575 != 0) {
576 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
577 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800578 } else {
Hui Yue9b40ba2020-03-05 17:16:27 -0800579 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
Hui Yubb866ad2020-03-04 12:33:40 -0800580 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800581 }
Hui Yu85679b42020-01-15 15:52:08 -0800582 case OP_RECORD_AUDIO:
Hui Yu88910de2019-12-16 14:35:27 -0800583 if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
Hui Yubb866ad2020-03-04 12:33:40 -0800584 return MODE_ALLOWED;
Hui Yu77fd8192020-03-27 00:22:57 -0700585 } else if ((capability
586 & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) != 0) {
Hui Yue9b40ba2020-03-05 17:16:27 -0800587 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
588 return MODE_ALLOWED;
Hui Yu77fd8192020-03-27 00:22:57 -0700589 } else if ((capability
590 & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
591 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
592 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800593 } else {
Hui Yue9b40ba2020-03-05 17:16:27 -0800594 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
Hui Yubb866ad2020-03-04 12:33:40 -0800595 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800596 }
Hui Yu26969322019-08-21 14:56:35 -0700597 default:
Hui Yubb866ad2020-03-04 12:33:40 -0800598 return MODE_ALLOWED;
Hui Yu26969322019-08-21 14:56:35 -0700599 }
600 } else {
601 // process is not in foreground.
Hui Yubb866ad2020-03-04 12:33:40 -0800602 return MODE_IGNORED;
Hui Yu26969322019-08-21 14:56:35 -0700603 }
Hui Yubb866ad2020-03-04 12:33:40 -0800604 } else if (mode == MODE_ALLOWED) {
Hui Yu88910de2019-12-16 14:35:27 -0800605 switch (op) {
606 case OP_CAMERA:
607 if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
Hui Yubb866ad2020-03-04 12:33:40 -0800608 return MODE_ALLOWED;
Hui Yu77fd8192020-03-27 00:22:57 -0700609 } else if ((capability
610 & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) != 0) {
Hui Yue9b40ba2020-03-05 17:16:27 -0800611 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
612 return MODE_ALLOWED;
Hui Yu77fd8192020-03-27 00:22:57 -0700613 } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
614 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
615 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800616 } else {
Hui Yue9b40ba2020-03-05 17:16:27 -0800617 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
Hui Yubb866ad2020-03-04 12:33:40 -0800618 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800619 }
620 case OP_RECORD_AUDIO:
621 if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
Hui Yubb866ad2020-03-04 12:33:40 -0800622 return MODE_ALLOWED;
Hui Yu77fd8192020-03-27 00:22:57 -0700623 } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q)
Hui Yue9b40ba2020-03-05 17:16:27 -0800624 != 0) {
Hui Yue9b40ba2020-03-05 17:16:27 -0800625 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
626 return MODE_ALLOWED;
Hui Yu77fd8192020-03-27 00:22:57 -0700627 } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE)
628 != 0) {
629 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
630 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800631 } else {
Hui Yue9b40ba2020-03-05 17:16:27 -0800632 maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
Hui Yubb866ad2020-03-04 12:33:40 -0800633 return MODE_IGNORED;
Hui Yu88910de2019-12-16 14:35:27 -0800634 }
635 default:
636 return MODE_ALLOWED;
637 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700638 }
639 return mode;
640 }
641
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700642 private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
643 SparseBooleanArray which) {
644 boolean curValue = which.get(op, false);
645 ArraySet<ModeCallback> callbacks = watchers.get(op);
646 if (callbacks != null) {
647 for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
648 if ((callbacks.valueAt(cbi).mFlags
649 & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
650 hasForegroundWatchers = true;
651 curValue = true;
652 }
653 }
654 }
655 which.put(op, curValue);
656 }
657
658 public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700659 SparseBooleanArray which = null;
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700660 hasForegroundWatchers = false;
Hai Zhang93540ca2019-09-28 00:04:18 +0000661 if (opModes != null) {
662 for (int i = opModes.size() - 1; i >= 0; i--) {
663 if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
664 if (which == null) {
665 which = new SparseBooleanArray();
666 }
667 evalForegroundWatchers(opModes.keyAt(i), watchers, which);
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700668 }
669 }
670 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700671 if (pkgOps != null) {
672 for (int i = pkgOps.size() - 1; i >= 0; i--) {
673 Ops ops = pkgOps.valueAt(i);
674 for (int j = ops.size() - 1; j >= 0; j--) {
675 if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
676 if (which == null) {
677 which = new SparseBooleanArray();
678 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -0700679 evalForegroundWatchers(ops.keyAt(j), watchers, which);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -0700680 }
681 }
682 }
683 }
684 foregroundOps = which;
685 }
Hui Yu88910de2019-12-16 14:35:27 -0800686
687 // TODO: remove this toast after feature development is done
Hui Yud3de0b92020-03-18 16:33:37 -0700688 // For DEBUG_FGS_ALLOW_WHILE_IN_USE, if the procstate is foreground service and while-in-use
689 // permission is denied, show a toast message and generate a WTF log so we know
690 // how many apps are impacted by the new background started foreground service while-in-use
691 // permission restriction.
692 // For DEBUG_FGS_ENFORCE_TYPE, The process has a foreground service that does not have
693 // camera/microphone foregroundServiceType in manifest file, and the process is asking
694 // AppOps for camera/microphone ops, show a toast message and generate a WTF log.
Hui Yu88910de2019-12-16 14:35:27 -0800695 void maybeShowWhileInUseDebugToast(int op, int mode) {
Hui Yud3de0b92020-03-18 16:33:37 -0700696 if (mode == DEBUG_FGS_ALLOW_WHILE_IN_USE && state != UID_STATE_FOREGROUND_SERVICE) {
Hui Yu88910de2019-12-16 14:35:27 -0800697 return;
698 }
699 final long now = System.currentTimeMillis();
Hui Yud3de0b92020-03-18 16:33:37 -0700700 if (lastTimeShowDebugToast == 0 || now - lastTimeShowDebugToast > 600000) {
Hui Yu88910de2019-12-16 14:35:27 -0800701 lastTimeShowDebugToast = now;
702 mHandler.sendMessage(PooledLambda.obtainMessage(
703 ActivityManagerInternal::showWhileInUseDebugToast,
704 mActivityManagerInternal, uid, op, mode));
705 }
706 }
Svet Ganov2af57082015-07-30 08:44:20 -0700707 }
708
Dianne Hackborncd1f30b2018-04-23 17:38:09 -0700709 final static class Ops extends SparseArray<Op> {
710 final String packageName;
711 final UidState uidState;
Philip P. Moltmannad787aa2020-03-10 09:49:22 -0700712
713 /**
714 * The restriction properties of the package. If {@code null} it could not have been read
715 * yet and has to be refreshed.
716 */
717 @Nullable RestrictionBypass bypass;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800718
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800719 /** Lazily populated cache of attributionTags of this package */
720 final @NonNull ArraySet<String> knownAttributionTags = new ArraySet<>();
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800721
Philip P. Moltmannad787aa2020-03-10 09:49:22 -0700722 Ops(String _packageName, UidState _uidState) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800723 packageName = _packageName;
Svet Ganov2af57082015-07-30 08:44:20 -0700724 uidState = _uidState;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800725 }
726 }
727
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800728 /** A in progress startOp->finishOp event */
729 private static final class InProgressStartOpEvent implements IBinder.DeathRecipient {
Philip P. Moltmanne6ece902020-01-02 13:31:10 -0800730 /** Wall clock time of startOp event (not monotonic) */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800731 private long mStartTime;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800732
Philip P. Moltmanne6ece902020-01-02 13:31:10 -0800733 /** Elapsed time since boot of startOp event */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800734 private long mStartElapsedTime;
Philip P. Moltmanne6ece902020-01-02 13:31:10 -0800735
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800736 /** Id of the client that started the event */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800737 private @NonNull IBinder mClientId;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800738
739 /** To call when client dies */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800740 private @NonNull Runnable mOnDeath;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800741
742 /** uidstate used when calling startOp */
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800743 private @AppOpsManager.UidState int mUidState;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800744
745 /** How many times the op was started but not finished yet */
746 int numUnfinishedStarts;
747
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800748 /**
749 * Create a new {@link InProgressStartOpEvent}.
750 *
751 * @param startTime The time {@link #startOperation} was called
752 * @param startElapsedTime The elapsed time when {@link #startOperation} was called
753 * @param clientId The client id of the caller of {@link #startOperation}
754 * @param onDeath The code to execute on client death
755 * @param uidState The uidstate of the app {@link #startOperation} was called for
756 *
757 * @throws RemoteException If the client is dying
758 */
Philip P. Moltmanne6ece902020-01-02 13:31:10 -0800759 private InProgressStartOpEvent(long startTime, long startElapsedTime,
760 @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState)
761 throws RemoteException {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800762 mStartTime = startTime;
763 mStartElapsedTime = startElapsedTime;
764 mClientId = clientId;
765 mOnDeath = onDeath;
766 mUidState = uidState;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800767
768 clientId.linkToDeath(this, 0);
769 }
770
771 /** Clean up event */
772 public void finish() {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800773 mClientId.unlinkToDeath(this, 0);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800774 }
775
776 @Override
777 public void binderDied() {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800778 mOnDeath.run();
779 }
780
781 /**
782 * Reinit existing object with new state.
783 *
784 * @param startTime The time {@link #startOperation} was called
785 * @param startElapsedTime The elapsed time when {@link #startOperation} was called
786 * @param clientId The client id of the caller of {@link #startOperation}
787 * @param onDeath The code to execute on client death
788 * @param uidState The uidstate of the app {@link #startOperation} was called for
789 *
790 * @throws RemoteException If the client is dying
791 */
792 public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId,
793 @NonNull Runnable onDeath, int uidState) throws RemoteException {
794 mStartTime = startTime;
795 mStartElapsedTime = startElapsedTime;
796 mClientId = clientId;
797 mOnDeath = onDeath;
798 mUidState = uidState;
799
800 clientId.linkToDeath(this, 0);
801 }
802
803 /** @return Wall clock time of startOp event */
804 public long getStartTime() {
805 return mStartTime;
806 }
807
808 /** @return Elapsed time since boot of startOp event */
809 public long getStartElapsedTime() {
810 return mStartElapsedTime;
811 }
812
813 /** @return Id of the client that started the event */
814 public @NonNull IBinder getClientId() {
815 return mClientId;
816 }
817
818 /** @return uidstate used when calling startOp */
819 public int getUidState() {
820 return mUidState;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800821 }
822 }
823
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800824 private final class AttributedOp {
825 public final @Nullable String tag;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700826 public final @NonNull Op parent;
Svet Ganovaf189e32019-02-15 18:45:29 -0800827
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800828 /**
829 * Last successful accesses (noteOp + finished startOp) for each uidState/opFlag combination
830 *
831 * <p>Key is {@link AppOpsManager#makeKey}
832 */
833 @GuardedBy("AppOpsService.this")
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800834 private @Nullable LongSparseArray<NoteOpEvent> mAccessEvents;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800835
836 /**
837 * Last rejected accesses for each uidState/opFlag combination
838 *
839 * <p>Key is {@link AppOpsManager#makeKey}
840 */
841 @GuardedBy("AppOpsService.this")
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800842 private @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
Svet Ganovaf189e32019-02-15 18:45:29 -0800843
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800844 /**
845 * Currently in progress startOp events
846 *
847 * <p>Key is clientId
848 */
849 @GuardedBy("AppOpsService.this")
850 private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mInProgressEvents;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700851
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800852 AttributedOp(@Nullable String tag, @NonNull Op parent) {
853 this.tag = tag;
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700854 this.parent = parent;
855 }
856
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800857 /**
858 * Update state when noteOp was rejected or startOp->finishOp event finished
859 *
860 * @param proxyUid The uid of the proxy
861 * @param proxyPackageName The package name of the proxy
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800862 * @param proxyAttributionTag the attributionTag in the proxies package
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800863 * @param uidState UID state of the app noteOp/startOp was called for
864 * @param flags OpFlags of the call
865 */
866 public void accessed(int proxyUid, @Nullable String proxyPackageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800867 @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700868 @OpFlags int flags) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800869 accessed(System.currentTimeMillis(), -1, proxyUid, proxyPackageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800870 proxyAttributionTag, uidState, flags);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -0800871
872 mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800873 tag, uidState, flags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700874 }
875
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800876 /**
877 * Add an access that was previously collected.
878 *
879 * @param noteTime The time of the event
880 * @param duration The duration of the event
881 * @param proxyUid The uid of the proxy
882 * @param proxyPackageName The package name of the proxy
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800883 * @param proxyAttributionTag the attributionTag in the proxies package
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800884 * @param uidState UID state of the app noteOp/startOp was called for
885 * @param flags OpFlags of the call
886 */
887 public void accessed(long noteTime, long duration, int proxyUid,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800888 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700889 @AppOpsManager.UidState int uidState, @OpFlags int flags) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800890 long key = makeKey(uidState, flags);
891
892 if (mAccessEvents == null) {
893 mAccessEvents = new LongSparseArray<>(1);
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700894 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800895
896 OpEventProxyInfo proxyInfo = null;
897 if (proxyUid != Process.INVALID_UID) {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800898 proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800899 proxyAttributionTag);
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700900 }
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800901
902 NoteOpEvent existingEvent = mAccessEvents.get(key);
903 if (existingEvent != null) {
904 existingEvent.reinit(noteTime, duration, proxyInfo, mOpEventProxyInfoPool);
905 } else {
906 mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo));
907 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700908 }
909
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800910 /**
911 * Update state when noteOp/startOp was rejected.
912 *
913 * @param uidState UID state of the app noteOp is called for
914 * @param flags OpFlags of the call
915 */
916 public void rejected(@AppOpsManager.UidState int uidState, @OpFlags int flags) {
917 rejected(System.currentTimeMillis(), uidState, flags);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -0800918
919 mHistoricalRegistry.incrementOpRejected(parent.op, parent.uid, parent.packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800920 tag, uidState, flags);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800921 }
922
923 /**
924 * Add an rejection that was previously collected
925 *
926 * @param noteTime The time of the event
927 * @param uidState UID state of the app noteOp/startOp was called for
928 * @param flags OpFlags of the call
929 */
930 public void rejected(long noteTime, @AppOpsManager.UidState int uidState,
931 @OpFlags int flags) {
932 long key = makeKey(uidState, flags);
933
934 if (mRejectEvents == null) {
935 mRejectEvents = new LongSparseArray<>(1);
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700936 }
937
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800938 // We do not collect proxy information for rejections yet
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800939 NoteOpEvent existingEvent = mRejectEvents.get(key);
940 if (existingEvent != null) {
941 existingEvent.reinit(noteTime, -1, null, mOpEventProxyInfoPool);
942 } else {
943 mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null));
944 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800945 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700946
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800947 /**
948 * Update state when start was called
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800949 *
950 * @param clientId Id of the startOp caller
951 * @param uidState UID state of the app startOp is called for
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800952 */
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800953 public void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState)
954 throws RemoteException {
Philip P. Moltmann494b4ab2020-01-31 09:33:20 -0800955 started(clientId, uidState, true);
956 }
957
958 private void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState,
959 boolean triggerCallbackIfNeeded) throws RemoteException {
960 if (triggerCallbackIfNeeded && !parent.isRunning()) {
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800961 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
962 parent.packageName, true);
963 }
964
965 if (mInProgressEvents == null) {
966 mInProgressEvents = new ArrayMap<>(1);
967 }
968
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800969 InProgressStartOpEvent event = mInProgressEvents.get(clientId);
970 if (event == null) {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800971 event = mInProgressStartOpEventPool.acquire(System.currentTimeMillis(),
972 SystemClock.elapsedRealtime(), clientId,
973 PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
974 uidState);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800975 mInProgressEvents.put(clientId, event);
976 } else {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -0800977 if (uidState != event.mUidState) {
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800978 onUidStateChanged(uidState);
979 }
980 }
981
982 event.numUnfinishedStarts++;
983
984 // startOp events don't support proxy, hence use flags==SELF
985 mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800986 tag, uidState, OP_FLAG_SELF);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800987 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -0700988
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800989 /**
990 * Update state when finishOp was called
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800991 *
992 * @param clientId Id of the finishOp caller
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -0800993 */
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -0800994 public void finished(@NonNull IBinder clientId) {
995 finished(clientId, true);
996 }
997
998 private void finished(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded) {
999 if (mInProgressEvents == null) {
1000 Slog.wtf(TAG, "No ops running");
1001 return;
1002 }
1003
1004 int indexOfToken = mInProgressEvents.indexOfKey(clientId);
1005 if (indexOfToken < 0) {
1006 Slog.wtf(TAG, "No op running for the client");
1007 return;
1008 }
1009
1010 InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken);
1011 event.numUnfinishedStarts--;
1012 if (event.numUnfinishedStarts == 0) {
1013 event.finish();
1014 mInProgressEvents.removeAt(indexOfToken);
1015
1016 if (mAccessEvents == null) {
1017 mAccessEvents = new LongSparseArray<>(1);
1018 }
1019
1020 // startOp events don't support proxy, hence use flags==SELF
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001021 NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(),
1022 SystemClock.elapsedRealtime() - event.getStartElapsedTime(), null);
1023 mAccessEvents.put(makeKey(event.getUidState(), OP_FLAG_SELF), finishedEvent);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001024
1025 mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001026 parent.packageName, tag, event.getUidState(),
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08001027 AppOpsManager.OP_FLAG_SELF, finishedEvent.getDuration());
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001028
1029 mInProgressStartOpEventPool.release(event);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001030
1031 if (mInProgressEvents.isEmpty()) {
1032 mInProgressEvents = null;
1033
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001034 // TODO moltmann: Also callback for single attribution tag activity changes
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001035 if (triggerCallbackIfNeeded && !parent.isRunning()) {
1036 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
1037 parent.packageName, false);
1038 }
1039 }
1040 }
1041 }
1042
1043 /**
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001044 * Called in the case the client dies without calling finish first
1045 *
1046 * @param clientId The client that died
1047 */
1048 void onClientDeath(@NonNull IBinder clientId) {
1049 synchronized (AppOpsService.this) {
1050 if (mInProgressEvents == null) {
1051 return;
1052 }
1053
1054 InProgressStartOpEvent deadEvent = mInProgressEvents.get(clientId);
1055 if (deadEvent != null) {
1056 deadEvent.numUnfinishedStarts = 1;
1057 }
1058
1059 finished(clientId);
1060 }
1061 }
1062
1063 /**
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001064 * Notify that the state of the uid changed
1065 *
1066 * @param newState The new state
1067 */
1068 public void onUidStateChanged(@AppOpsManager.UidState int newState) {
1069 if (mInProgressEvents == null) {
1070 return;
1071 }
1072
1073 int numInProgressEvents = mInProgressEvents.size();
1074 for (int i = 0; i < numInProgressEvents; i++) {
1075 InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
1076
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001077 if (event.getUidState() != newState) {
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001078 try {
Philip P. Moltmann494b4ab2020-01-31 09:33:20 -08001079 // Remove all but one unfinished start count and then call finished() to
1080 // remove start event object
1081 int numPreviousUnfinishedStarts = event.numUnfinishedStarts;
1082 event.numUnfinishedStarts = 1;
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001083 finished(event.getClientId(), false);
Philip P. Moltmann494b4ab2020-01-31 09:33:20 -08001084
1085 // Call started() to add a new start event object and then add the
1086 // previously removed unfinished start counts back
1087 started(event.getClientId(), newState, false);
1088 event.numUnfinishedStarts += numPreviousUnfinishedStarts - 1;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001089 } catch (RemoteException e) {
1090 if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
1091 }
1092 }
1093 }
1094 }
1095
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001096 /**
1097 * Combine {@code a} and {@code b} and return the result. The result might be {@code a}
1098 * or {@code b}. If there is an event for the same key in both the later event is retained.
1099 */
1100 private @Nullable LongSparseArray<NoteOpEvent> add(@Nullable LongSparseArray<NoteOpEvent> a,
1101 @Nullable LongSparseArray<NoteOpEvent> b) {
1102 if (a == null) {
1103 return b;
1104 }
1105
1106 if (b == null) {
1107 return a;
1108 }
1109
1110 int numEventsToAdd = b.size();
1111 for (int i = 0; i < numEventsToAdd; i++) {
1112 long keyOfEventToAdd = b.keyAt(i);
1113 NoteOpEvent bEvent = b.valueAt(i);
1114 NoteOpEvent aEvent = a.get(keyOfEventToAdd);
1115
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001116 if (aEvent == null || bEvent.getNoteTime() > aEvent.getNoteTime()) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001117 a.put(keyOfEventToAdd, bEvent);
1118 }
1119 }
1120
1121 return a;
1122 }
1123
1124 /**
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001125 * Add all data from the {@code opToAdd} to this op.
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001126 *
1127 * <p>If there is an event for the same key in both the later event is retained.
1128 * <p>{@code opToAdd} should not be used after this method is called.
1129 *
1130 * @param opToAdd The op to add
1131 */
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001132 public void add(@NonNull AttributedOp opToAdd) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001133 if (opToAdd.mInProgressEvents != null) {
1134 Slog.w(TAG, "Ignoring " + opToAdd.mInProgressEvents.size() + " running app-ops");
1135
1136 int numInProgressEvents = opToAdd.mInProgressEvents.size();
1137 for (int i = 0; i < numInProgressEvents; i++) {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001138 InProgressStartOpEvent event = opToAdd.mInProgressEvents.valueAt(i);
1139
1140 event.finish();
1141 mInProgressStartOpEventPool.release(event);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001142 }
1143 }
1144
1145 mAccessEvents = add(mAccessEvents, opToAdd.mAccessEvents);
1146 mRejectEvents = add(mRejectEvents, opToAdd.mRejectEvents);
1147 }
1148
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001149 public boolean isRunning() {
1150 return mInProgressEvents != null;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001151 }
1152
1153 boolean hasAnyTime() {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001154 return (mAccessEvents != null && mAccessEvents.size() > 0)
1155 || (mRejectEvents != null && mRejectEvents.size() > 0);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001156 }
1157
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001158 /**
1159 * Clone a {@link LongSparseArray} and clone all values.
1160 */
1161 private @Nullable LongSparseArray<NoteOpEvent> deepClone(
1162 @Nullable LongSparseArray<NoteOpEvent> original) {
1163 if (original == null) {
1164 return original;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001165 }
1166
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001167 int size = original.size();
1168 LongSparseArray<NoteOpEvent> clone = new LongSparseArray<>(size);
1169 for (int i = 0; i < size; i++) {
1170 clone.put(original.keyAt(i), new NoteOpEvent(original.valueAt(i)));
1171 }
1172
1173 return clone;
1174 }
1175
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001176 @NonNull AttributedOpEntry createAttributedOpEntryLocked() {
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001177 LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents);
1178
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001179 // Add in progress events as access events
1180 if (mInProgressEvents != null) {
Philip P. Moltmanne6ece902020-01-02 13:31:10 -08001181 long now = SystemClock.elapsedRealtime();
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001182 int numInProgressEvents = mInProgressEvents.size();
1183
1184 if (accessEvents == null) {
1185 accessEvents = new LongSparseArray<>(numInProgressEvents);
1186 }
1187
1188 for (int i = 0; i < numInProgressEvents; i++) {
1189 InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
1190
1191 // startOp events don't support proxy
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001192 accessEvents.append(makeKey(event.getUidState(), OP_FLAG_SELF),
1193 new NoteOpEvent(event.getStartTime(), now - event.getStartElapsedTime(),
1194 null));
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001195 }
1196 }
1197
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001198 LongSparseArray<NoteOpEvent> rejectEvents = deepClone(mRejectEvents);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001199
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001200 return new AttributedOpEntry(parent.op, isRunning(), accessEvents, rejectEvents);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001201 }
1202 }
1203
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001204 final class Op {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001205 int op;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001206 int uid;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001207 final UidState uidState;
1208 final @NonNull String packageName;
1209
1210 private @Mode int mode;
1211
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001212 /** attributionTag -> AttributedOp */
1213 final ArrayMap<String, AttributedOp> mAttributions = new ArrayMap<>(1);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001214
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001215 Op(UidState uidState, String packageName, int op, int uid) {
Svet Ganovaf189e32019-02-15 18:45:29 -08001216 this.op = op;
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001217 this.uid = uid;
Svet Ganovaf189e32019-02-15 18:45:29 -08001218 this.uidState = uidState;
1219 this.packageName = packageName;
1220 this.mode = AppOpsManager.opToDefaultMode(op);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001221 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001222
1223 int getMode() {
Svet Ganovaf189e32019-02-15 18:45:29 -08001224 return mode;
1225 }
1226
1227 int evalMode() {
1228 return uidState.evalMode(op, mode);
1229 }
1230
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001231 void removeAttributionsWithNoTime() {
1232 for (int i = mAttributions.size() - 1; i >= 0; i--) {
1233 if (!mAttributions.valueAt(i).hasAnyTime()) {
1234 mAttributions.removeAt(i);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001235 }
Svet Ganovaf189e32019-02-15 18:45:29 -08001236 }
1237 }
1238
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001239 private @NonNull AttributedOp getOrCreateAttribution(@NonNull Op parent,
1240 @Nullable String attributionTag) {
1241 AttributedOp attributedOp;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001242
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001243 attributedOp = mAttributions.get(attributionTag);
1244 if (attributedOp == null) {
1245 attributedOp = new AttributedOp(attributionTag, parent);
1246 mAttributions.put(attributionTag, attributedOp);
Svet Ganovaf189e32019-02-15 18:45:29 -08001247 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001248
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001249 return attributedOp;
Svet Ganovaf189e32019-02-15 18:45:29 -08001250 }
1251
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001252 @NonNull OpEntry createEntryLocked() {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001253 final int numAttributions = mAttributions.size();
Svet Ganovaf189e32019-02-15 18:45:29 -08001254
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001255 final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
1256 new ArrayMap<>(numAttributions);
1257 for (int i = 0; i < numAttributions; i++) {
1258 attributionEntries.put(mAttributions.keyAt(i),
1259 mAttributions.valueAt(i).createAttributedOpEntryLocked());
Philip P. Moltmann4052d362019-09-19 14:52:38 -07001260 }
1261
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001262 return new OpEntry(op, mode, attributionEntries);
Svet Ganovaf189e32019-02-15 18:45:29 -08001263 }
1264
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001265 @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
1266 final int numAttributions = mAttributions.size();
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001267
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001268 final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
1269 for (int i = 0; i < numAttributions; i++) {
1270 if (Objects.equals(mAttributions.keyAt(i), attributionTag)) {
1271 attributionEntries.put(mAttributions.keyAt(i),
1272 mAttributions.valueAt(i).createAttributedOpEntryLocked());
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001273 break;
1274 }
1275 }
1276
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001277 return new OpEntry(op, mode, attributionEntries);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001278 }
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001279
1280 boolean isRunning() {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001281 final int numAttributions = mAttributions.size();
1282 for (int i = 0; i < numAttributions; i++) {
1283 if (mAttributions.valueAt(i).isRunning()) {
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001284 return true;
1285 }
1286 }
1287
1288 return false;
1289 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001290 }
1291
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001292 final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
1293 final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
1294 final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
1295 final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
Adam Bookatz182862e2020-04-27 21:58:22 -07001296 final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>();
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001297 final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07001298 final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
Dianne Hackbornc2293022013-02-06 23:14:49 -08001299
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001300 final class ModeCallback implements DeathRecipient {
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08001301 /** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */
1302 public static final int ALL_OPS = -2;
1303
Dianne Hackbornc2293022013-02-06 23:14:49 -08001304 final IAppOpsCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001305 final int mWatchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001306 final int mFlags;
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08001307 final int mWatchedOpCode;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001308 final int mCallingUid;
1309 final int mCallingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001310
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08001311 ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp,
1312 int callingUid, int callingPid) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001313 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001314 mWatchingUid = watchingUid;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001315 mFlags = flags;
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08001316 mWatchedOpCode = watchedOp;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001317 mCallingUid = callingUid;
1318 mCallingPid = callingPid;
Dianne Hackbornc2293022013-02-06 23:14:49 -08001319 try {
1320 mCallback.asBinder().linkToDeath(this, 0);
1321 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001322 /*ignored*/
Dianne Hackbornc2293022013-02-06 23:14:49 -08001323 }
1324 }
1325
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001326 public boolean isWatchingUid(int uid) {
1327 return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
1328 }
1329
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001330 @Override
1331 public String toString() {
1332 StringBuilder sb = new StringBuilder(128);
1333 sb.append("ModeCallback{");
1334 sb.append(Integer.toHexString(System.identityHashCode(this)));
1335 sb.append(" watchinguid=");
1336 UserHandle.formatUid(sb, mWatchingUid);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001337 sb.append(" flags=0x");
1338 sb.append(Integer.toHexString(mFlags));
Philip P. Moltmannb992f8c2020-02-14 10:35:24 -08001339 switch (mWatchedOpCode) {
1340 case OP_NONE:
1341 break;
1342 case ALL_OPS:
1343 sb.append(" op=(all)");
1344 break;
1345 default:
1346 sb.append(" op=");
1347 sb.append(opToName(mWatchedOpCode));
1348 break;
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08001349 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001350 sb.append(" from uid=");
1351 UserHandle.formatUid(sb, mCallingUid);
1352 sb.append(" pid=");
1353 sb.append(mCallingPid);
1354 sb.append('}');
1355 return sb.toString();
1356 }
1357
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001358 void unlinkToDeath() {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001359 mCallback.asBinder().unlinkToDeath(this, 0);
1360 }
1361
1362 @Override
1363 public void binderDied() {
1364 stopWatchingMode(mCallback);
1365 }
1366 }
1367
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001368 final class ActiveCallback implements DeathRecipient {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001369 final IAppOpsActiveCallback mCallback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001370 final int mWatchingUid;
1371 final int mCallingUid;
1372 final int mCallingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001373
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001374 ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001375 int callingPid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001376 mCallback = callback;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001377 mWatchingUid = watchingUid;
1378 mCallingUid = callingUid;
1379 mCallingPid = callingPid;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001380 try {
1381 mCallback.asBinder().linkToDeath(this, 0);
1382 } catch (RemoteException e) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001383 /*ignored*/
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001384 }
1385 }
1386
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07001387 @Override
1388 public String toString() {
1389 StringBuilder sb = new StringBuilder(128);
1390 sb.append("ActiveCallback{");
1391 sb.append(Integer.toHexString(System.identityHashCode(this)));
1392 sb.append(" watchinguid=");
1393 UserHandle.formatUid(sb, mWatchingUid);
1394 sb.append(" from uid=");
1395 UserHandle.formatUid(sb, mCallingUid);
1396 sb.append(" pid=");
1397 sb.append(mCallingPid);
1398 sb.append('}');
1399 return sb.toString();
1400 }
1401
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001402 void destroy() {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001403 mCallback.asBinder().unlinkToDeath(this, 0);
1404 }
1405
1406 @Override
1407 public void binderDied() {
1408 stopWatchingActive(mCallback);
1409 }
1410 }
1411
Adam Bookatz182862e2020-04-27 21:58:22 -07001412 final class StartedCallback implements DeathRecipient {
1413 final IAppOpsStartedCallback mCallback;
1414 final int mWatchingUid;
1415 final int mCallingUid;
1416 final int mCallingPid;
1417
1418 StartedCallback(IAppOpsStartedCallback callback, int watchingUid, int callingUid,
1419 int callingPid) {
1420 mCallback = callback;
1421 mWatchingUid = watchingUid;
1422 mCallingUid = callingUid;
1423 mCallingPid = callingPid;
1424 try {
1425 mCallback.asBinder().linkToDeath(this, 0);
1426 } catch (RemoteException e) {
1427 /*ignored*/
1428 }
1429 }
1430
1431 @Override
1432 public String toString() {
1433 StringBuilder sb = new StringBuilder(128);
1434 sb.append("StartedCallback{");
1435 sb.append(Integer.toHexString(System.identityHashCode(this)));
1436 sb.append(" watchinguid=");
1437 UserHandle.formatUid(sb, mWatchingUid);
1438 sb.append(" from uid=");
1439 UserHandle.formatUid(sb, mCallingUid);
1440 sb.append(" pid=");
1441 sb.append(mCallingPid);
1442 sb.append('}');
1443 return sb.toString();
1444 }
1445
1446 void destroy() {
1447 mCallback.asBinder().unlinkToDeath(this, 0);
1448 }
1449
1450 @Override
1451 public void binderDied() {
1452 stopWatchingStarted(mCallback);
1453 }
1454 }
1455
Svet Ganovb3d2ae22018-12-17 22:06:15 -08001456 final class NotedCallback implements DeathRecipient {
1457 final IAppOpsNotedCallback mCallback;
1458 final int mWatchingUid;
1459 final int mCallingUid;
1460 final int mCallingPid;
1461
1462 NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
1463 int callingPid) {
1464 mCallback = callback;
1465 mWatchingUid = watchingUid;
1466 mCallingUid = callingUid;
1467 mCallingPid = callingPid;
1468 try {
1469 mCallback.asBinder().linkToDeath(this, 0);
1470 } catch (RemoteException e) {
1471 /*ignored*/
1472 }
1473 }
1474
1475 @Override
1476 public String toString() {
1477 StringBuilder sb = new StringBuilder(128);
1478 sb.append("NotedCallback{");
1479 sb.append(Integer.toHexString(System.identityHashCode(this)));
1480 sb.append(" watchinguid=");
1481 UserHandle.formatUid(sb, mWatchingUid);
1482 sb.append(" from uid=");
1483 UserHandle.formatUid(sb, mCallingUid);
1484 sb.append(" pid=");
1485 sb.append(mCallingPid);
1486 sb.append('}');
1487 return sb.toString();
1488 }
1489
1490 void destroy() {
1491 mCallback.asBinder().unlinkToDeath(this, 0);
1492 }
1493
1494 @Override
1495 public void binderDied() {
1496 stopWatchingNoted(mCallback);
1497 }
1498 }
1499
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001500 /**
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001501 * Call {@link AttributedOp#onClientDeath attributedOp.onClientDeath(clientId)}.
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001502 */
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001503 private static void onClientDeath(@NonNull AttributedOp attributedOp,
1504 @NonNull IBinder clientId) {
1505 attributedOp.onClientDeath(clientId);
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08001506 }
1507
David Cheung2ead9662020-02-19 16:11:06 -08001508
1509 /**
1510 * Loads the OpsValidation file results into a hashmap {@link #mNoteOpCallerStacktraces}
1511 * so that we do not log the same operation twice between instances
1512 */
1513 private void readNoteOpCallerStackTraces() {
1514 try {
1515 if (!mNoteOpCallerStacktracesFile.exists()) {
1516 mNoteOpCallerStacktracesFile.createNewFile();
1517 return;
1518 }
1519
1520 try (Scanner read = new Scanner(mNoteOpCallerStacktracesFile)) {
1521 read.useDelimiter("\\},");
1522 while (read.hasNext()) {
1523 String jsonOps = read.next();
1524 mNoteOpCallerStacktraces.add(NoteOpTrace.fromJson(jsonOps));
1525 }
1526 }
1527 } catch (Exception e) {
1528 Slog.e(TAG, "Cannot parse traces noteOps", e);
1529 }
1530 }
1531
Philip P. Moltmannfe2fc3a2020-02-05 16:59:39 -08001532 public AppOpsService(File storagePath, Handler handler, Context context) {
1533 mContext = context;
1534
Jeff Sharkey5f3e9342017-03-13 14:53:11 -06001535 LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
Dianne Hackborne17b4452018-01-10 13:15:40 -08001536 mFile = new AtomicFile(storagePath, "appops");
David Cheung2ead9662020-02-19 16:11:06 -08001537 if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED) {
1538 mNoteOpCallerStacktracesFile = new File(SystemServiceManager.ensureSystemDir(),
1539 "noteOpStackTraces.json");
1540 readNoteOpCallerStackTraces();
1541 } else {
1542 mNoteOpCallerStacktracesFile = null;
1543 }
Jeff Brown6f357d32014-01-15 20:40:55 -08001544 mHandler = handler;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001545 mConstants = new Constants(mHandler);
Dianne Hackborn35654b62013-01-14 17:38:02 -08001546 readState();
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08001547
1548 for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
1549 int switchCode = AppOpsManager.opToSwitch(switchedCode);
1550 mSwitchedOps.put(switchCode,
1551 ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
1552 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001553 }
David Braunf5d83192013-09-16 13:43:51 -07001554
Philip P. Moltmannfe2fc3a2020-02-05 16:59:39 -08001555 public void publish() {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001556 ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
Dianne Hackbornd5254412018-05-11 18:02:58 -07001557 LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001558 }
1559
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001560 /** Handler for work when packages are removed or updated */
1561 private BroadcastReceiver mOnPackageUpdatedReceiver = new BroadcastReceiver() {
1562 @Override
1563 public void onReceive(Context context, Intent intent) {
1564 String action = intent.getAction();
1565 String pkgName = intent.getData().getEncodedSchemeSpecificPart();
1566 int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
1567
1568 if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
1569 synchronized (AppOpsService.this) {
1570 UidState uidState = mUidStates.get(uid);
1571 if (uidState == null || uidState.pkgOps == null) {
1572 return;
1573 }
1574
1575 Ops removedOps = uidState.pkgOps.remove(pkgName);
1576 if (removedOps != null) {
1577 scheduleFastWriteLocked();
1578 }
1579 }
1580 } else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
1581 AndroidPackage pkg = LocalServices.getService(
1582 PackageManagerInternal.class).getPackage(pkgName);
1583 if (pkg == null) {
1584 return;
1585 }
1586
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001587 ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
1588 ArraySet<String> attributionTags = new ArraySet<>();
1589 attributionTags.add(null);
1590 if (pkg.getAttributions() != null) {
1591 int numAttributions = pkg.getAttributions().size();
1592 for (int attributionNum = 0; attributionNum < numAttributions;
1593 attributionNum++) {
1594 ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
1595 attributionTags.add(attribution.tag);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001596
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001597 int numInheritFrom = attribution.inheritFrom.size();
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001598 for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
1599 inheritFromNum++) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001600 dstAttributionTags.put(attribution.inheritFrom.get(inheritFromNum),
1601 attribution.tag);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001602 }
1603 }
1604 }
1605
1606 synchronized (AppOpsService.this) {
1607 UidState uidState = mUidStates.get(uid);
1608 if (uidState == null || uidState.pkgOps == null) {
1609 return;
1610 }
1611
1612 Ops ops = uidState.pkgOps.get(pkgName);
1613 if (ops == null) {
1614 return;
1615 }
1616
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07001617 // Reset cached package properties to re-initialize when needed
1618 ops.bypass = null;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001619 ops.knownAttributionTags.clear();
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07001620
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001621 // Merge data collected for removed attributions into their successor
1622 // attributions
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001623 int numOps = ops.size();
1624 for (int opNum = 0; opNum < numOps; opNum++) {
1625 Op op = ops.valueAt(opNum);
1626
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001627 int numAttributions = op.mAttributions.size();
1628 for (int attributionNum = numAttributions - 1; attributionNum >= 0;
1629 attributionNum--) {
1630 String attributionTag = op.mAttributions.keyAt(attributionNum);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001631
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001632 if (attributionTags.contains(attributionTag)) {
1633 // attribution still exist after upgrade
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001634 continue;
1635 }
1636
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001637 String newAttributionTag = dstAttributionTags.get(attributionTag);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001638
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001639 AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
1640 newAttributionTag);
1641 newAttributedOp.add(op.mAttributions.valueAt(attributionNum));
1642 op.mAttributions.removeAt(attributionNum);
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001643
1644 scheduleFastWriteLocked();
1645 }
1646 }
1647 }
1648 }
1649 }
1650 };
1651
Dianne Hackborn514074f2013-02-11 10:52:46 -08001652 public void systemReady() {
Dianne Hackborn45c79b02018-05-11 09:46:13 -07001653 mConstants.startMonitoring(mContext.getContentResolver());
Svet Ganov8455ba22019-01-02 13:05:56 -08001654 mHistoricalRegistry.systemReady(mContext.getContentResolver());
Dianne Hackborn45c79b02018-05-11 09:46:13 -07001655
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001656 IntentFilter packageUpdateFilter = new IntentFilter();
1657 packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1658 packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
1659 packageUpdateFilter.addDataScheme("package");
Svet Ganov2af57082015-07-30 08:44:20 -07001660
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001661 mContext.registerReceiver(mOnPackageUpdatedReceiver, packageUpdateFilter);
1662
1663 synchronized (this) {
1664 for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
1665 int uid = mUidStates.keyAt(uidNum);
1666 UidState uidState = mUidStates.valueAt(uidNum);
1667
1668 String[] pkgsInUid = getPackagesForUid(uidState.uid);
1669 if (ArrayUtils.isEmpty(pkgsInUid)) {
Svet Ganov2af57082015-07-30 08:44:20 -07001670 uidState.clear();
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001671 mUidStates.removeAt(uidNum);
1672 scheduleFastWriteLocked();
Svet Ganov2af57082015-07-30 08:44:20 -07001673 continue;
1674 }
1675
1676 ArrayMap<String, Ops> pkgs = uidState.pkgOps;
1677 if (pkgs == null) {
1678 continue;
1679 }
1680
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001681 int numPkgs = pkgs.size();
1682 for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
1683 String pkg = pkgs.keyAt(pkgNum);
Svet Ganov2af57082015-07-30 08:44:20 -07001684
Philip P. Moltmann9046d822019-12-13 15:59:49 -08001685 String action;
1686 if (!ArrayUtils.contains(pkgsInUid, pkg)) {
1687 action = Intent.ACTION_PACKAGE_REMOVED;
1688 } else {
1689 action = Intent.ACTION_PACKAGE_REPLACED;
1690 }
1691
1692 SystemServerInitThreadPool.submit(
1693 () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
1694 .setData(Uri.fromParts("package", pkg, null))
1695 .putExtra(Intent.EXTRA_UID, uid)),
1696 "Update app-ops uidState in case package " + pkg + " changed");
Dianne Hackborn514074f2013-02-11 10:52:46 -08001697 }
1698 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001699 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07001700
Suprabh Shukla3017fe42018-11-08 19:00:01 -08001701 final IntentFilter packageSuspendFilter = new IntentFilter();
1702 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
1703 packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1704 mContext.registerReceiver(new BroadcastReceiver() {
1705 @Override
1706 public void onReceive(Context context, Intent intent) {
1707 final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1708 final String[] changedPkgs = intent.getStringArrayExtra(
1709 Intent.EXTRA_CHANGED_PACKAGE_LIST);
Suprabh Shuklab614a222019-09-12 14:42:46 -07001710 for (int code : OPS_RESTRICTED_ON_SUSPEND) {
1711 ArraySet<ModeCallback> callbacks;
1712 synchronized (AppOpsService.this) {
1713 callbacks = mOpModeWatchers.get(code);
1714 if (callbacks == null) {
1715 continue;
1716 }
1717 callbacks = new ArraySet<>(callbacks);
Dianne Hackborn65e8de32019-04-04 11:01:41 -07001718 }
Suprabh Shuklab614a222019-09-12 14:42:46 -07001719 for (int i = 0; i < changedUids.length; i++) {
1720 final int changedUid = changedUids[i];
1721 final String changedPkg = changedPkgs[i];
1722 // We trust packagemanager to insert matching uid and packageNames in the
1723 // extras
Suprabh Shukla7e017922019-08-05 17:13:23 -07001724 notifyOpChanged(callbacks, code, changedUid, changedPkg);
1725 }
Suprabh Shukla3017fe42018-11-08 19:00:01 -08001726 }
1727 }
1728 }, packageSuspendFilter);
1729
Stanislav Zholnin90516b92020-01-20 14:03:06 +00001730 final IntentFilter packageAddedFilter = new IntentFilter();
1731 packageAddedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1732 packageAddedFilter.addDataScheme("package");
1733 mContext.registerReceiver(new BroadcastReceiver() {
1734 @Override
1735 public void onReceive(Context context, Intent intent) {
1736 final Uri data = intent.getData();
1737
1738 final String packageName = data.getSchemeSpecificPart();
1739 PackageInfo pi = LocalServices.getService(
1740 PackageManagerInternal.class).getPackageInfo(packageName,
1741 PackageManager.GET_PERMISSIONS, Process.myUid(), mContext.getUserId());
1742 if (isSamplingTarget(pi)) {
1743 synchronized (this) {
1744 mRarelyUsedPackages.add(packageName);
1745 }
1746 }
1747 }
1748 }, packageAddedFilter);
1749
Stanislav Zholnin4c323852020-03-04 18:03:24 +00001750 mHandler.postDelayed(new Runnable() {
Stanislav Zholnin90516b92020-01-20 14:03:06 +00001751 @Override
1752 public void run() {
Stanislav Zholnin4c323852020-03-04 18:03:24 +00001753 List<String> packageNames = getPackageNamesForSampling();
1754 resamplePackageAndAppOpLocked(packageNames);
Stanislav Zholnin90516b92020-01-20 14:03:06 +00001755 initializeRarelyUsedPackagesList(new ArraySet<>(packageNames));
1756 }
Stanislav Zholnin4c323852020-03-04 18:03:24 +00001757 }, RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS);
Stanislav Zholnin90516b92020-01-20 14:03:06 +00001758
Suprabh Shuklaaef25132017-01-23 18:09:03 -08001759 PackageManagerInternal packageManagerInternal = LocalServices.getService(
1760 PackageManagerInternal.class);
1761 packageManagerInternal.setExternalSourcesPolicy(
1762 new PackageManagerInternal.ExternalSourcesPolicy() {
1763 @Override
1764 public int getPackageTrustedToInstallApps(String packageName, int uid) {
1765 int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
1766 uid, packageName);
1767 switch (appOpMode) {
1768 case AppOpsManager.MODE_ALLOWED:
1769 return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
1770 case AppOpsManager.MODE_ERRORED:
1771 return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
1772 default:
1773 return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
1774 }
1775 }
1776 });
1777
Jeff Sharkey10ec9d82018-11-28 14:52:45 -07001778 if (!StorageManager.hasIsolatedStorage()) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -07001779 StorageManagerInternal storageManagerInternal = LocalServices.getService(
1780 StorageManagerInternal.class);
1781 storageManagerInternal.addExternalStoragePolicy(
1782 new StorageManagerInternal.ExternalStorageMountPolicy() {
1783 @Override
1784 public int getMountMode(int uid, String packageName) {
1785 if (Process.isIsolated(uid)) {
1786 return Zygote.MOUNT_EXTERNAL_NONE;
1787 }
1788 if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08001789 packageName, null, true, "External storage policy")
1790 != AppOpsManager.MODE_ALLOWED) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -07001791 return Zygote.MOUNT_EXTERNAL_NONE;
1792 }
1793 if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08001794 packageName, null, true, "External storage policy")
1795 != AppOpsManager.MODE_ALLOWED) {
Sudheer Shanka98cb3f02018-08-17 16:10:29 -07001796 return Zygote.MOUNT_EXTERNAL_READ;
1797 }
1798 return Zygote.MOUNT_EXTERNAL_WRITE;
Svet Ganov6ee871e2015-07-10 14:29:33 -07001799 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07001800
Sudheer Shanka98cb3f02018-08-17 16:10:29 -07001801 @Override
1802 public boolean hasExternalStorage(int uid, String packageName) {
1803 final int mountMode = getMountMode(uid, packageName);
1804 return mountMode == Zygote.MOUNT_EXTERNAL_READ
1805 || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
1806 }
1807 });
1808 }
Hui Yu88910de2019-12-16 14:35:27 -08001809 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001810 }
1811
1812 public void packageRemoved(int uid, String packageName) {
1813 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001814 UidState uidState = mUidStates.get(uid);
1815 if (uidState == null) {
1816 return;
1817 }
1818
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001819 Ops ops = null;
Svet Ganov2af57082015-07-30 08:44:20 -07001820
1821 // Remove any package state if such.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001822 if (uidState.pkgOps != null) {
1823 ops = uidState.pkgOps.remove(packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07001824 }
1825
1826 // If we just nuked the last package state check if the UID is valid.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001827 if (ops != null && uidState.pkgOps.isEmpty()
Svet Ganov2af57082015-07-30 08:44:20 -07001828 && getPackagesForUid(uid).length <= 0) {
1829 mUidStates.remove(uid);
1830 }
1831
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001832 if (ops != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07001833 scheduleFastWriteLocked();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001834
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001835 final int numOps = ops.size();
1836 for (int opNum = 0; opNum < numOps; opNum++) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001837 final Op op = ops.valueAt(opNum);
1838
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001839 final int numAttributions = op.mAttributions.size();
1840 for (int attributionNum = 0; attributionNum < numAttributions;
1841 attributionNum++) {
1842 AttributedOp attributedOp = op.mAttributions.valueAt(attributionNum);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001843
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001844 while (attributedOp.mInProgressEvents != null) {
1845 attributedOp.finished(attributedOp.mInProgressEvents.keyAt(0));
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001846 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08001847 }
1848 }
Dianne Hackborn514074f2013-02-11 10:52:46 -08001849 }
Winson470b15b2019-05-07 16:29:59 -07001850
1851 mHistoricalRegistry.clearHistory(uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08001852 }
1853 }
1854
1855 public void uidRemoved(int uid) {
1856 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07001857 if (mUidStates.indexOfKey(uid) >= 0) {
1858 mUidStates.remove(uid);
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08001859 scheduleFastWriteLocked();
Dianne Hackborn514074f2013-02-11 10:52:46 -08001860 }
1861 }
1862 }
1863
Philip P. Moltmann463979e2020-01-24 14:41:22 -08001864 /**
1865 * Update the pending state for the uid
1866 *
1867 * @param currentTime The current elapsed real time
1868 * @param uid The uid that has a pending state
1869 */
1870 private void updatePendingState(long currentTime, int uid) {
1871 synchronized (this) {
1872 mLastRealtime = max(currentTime, mLastRealtime);
1873 updatePendingStateIfNeededLocked(mUidStates.get(uid));
1874 }
1875 }
1876
Hui Yu26969322019-08-21 14:56:35 -07001877 public void updateUidProcState(int uid, int procState,
1878 @ActivityManager.ProcessCapability int capability) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001879 synchronized (this) {
1880 final UidState uidState = getUidStateLocked(uid, true);
Hui Yu26969322019-08-21 14:56:35 -07001881 final int newState = PROCESS_STATE_TO_UID_STATE[procState];
1882 if (uidState != null && (uidState.pendingState != newState
1883 || uidState.pendingCapability != capability)) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001884 final int oldPendingState = uidState.pendingState;
1885 uidState.pendingState = newState;
Hui Yu26969322019-08-21 14:56:35 -07001886 uidState.pendingCapability = capability;
Wei Wang878d0b62019-03-28 18:12:18 -07001887 if (newState < uidState.state
1888 || (newState <= UID_STATE_MAX_LAST_NON_RESTRICTED
1889 && uidState.state > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
1890 // We are moving to a more important state, or the new state may be in the
1891 // foreground and the old state is in the background, then always do it
1892 // immediately.
Dianne Hackborn65a4f252018-05-08 17:30:48 -07001893 commitUidPendingStateLocked(uidState);
Hui Yu26969322019-08-21 14:56:35 -07001894 } else if (newState == uidState.state && capability != uidState.capability) {
1895 // No change on process state, but process capability has changed.
1896 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001897 } else if (uidState.pendingStateCommitTime == 0) {
1898 // We are moving to a less important state for the first time,
1899 // delay the application for a bit.
Dianne Hackborne93ab412018-05-14 17:52:30 -07001900 final long settleTime;
1901 if (uidState.state <= UID_STATE_TOP) {
1902 settleTime = mConstants.TOP_STATE_SETTLE_TIME;
1903 } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
1904 settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
1905 } else {
1906 settleTime = mConstants.BG_STATE_SETTLE_TIME;
1907 }
Philip P. Moltmann463979e2020-01-24 14:41:22 -08001908 final long commitTime = SystemClock.elapsedRealtime() + settleTime;
1909 uidState.pendingStateCommitTime = commitTime;
1910
1911 mHandler.sendMessageDelayed(
1912 PooledLambda.obtainMessage(AppOpsService::updatePendingState, this,
1913 commitTime + 1, uid), settleTime + 1);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07001914 }
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001915
1916 if (uidState.pkgOps != null) {
1917 int numPkgs = uidState.pkgOps.size();
1918 for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
1919 Ops ops = uidState.pkgOps.valueAt(pkgNum);
1920
1921 int numOps = ops.size();
1922 for (int opNum = 0; opNum < numOps; opNum++) {
1923 Op op = ops.valueAt(opNum);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001924
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001925 int numAttributions = op.mAttributions.size();
1926 for (int attributionNum = 0; attributionNum < numAttributions;
1927 attributionNum++) {
1928 AttributedOp attributedOp = op.mAttributions.valueAt(
1929 attributionNum);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08001930
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08001931 attributedOp.onUidStateChanged(newState);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001932 }
1933 }
1934 }
1935 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001936 }
1937 }
1938 }
1939
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001940 public void shutdown() {
1941 Slog.w(TAG, "Writing app ops before shutdown...");
Dianne Hackborn35654b62013-01-14 17:38:02 -08001942 boolean doWrite = false;
1943 synchronized (this) {
1944 if (mWriteScheduled) {
1945 mWriteScheduled = false;
1946 doWrite = true;
1947 }
1948 }
1949 if (doWrite) {
1950 writeState();
1951 }
David Cheung2ead9662020-02-19 16:11:06 -08001952 if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED && mWriteNoteOpsScheduled) {
1953 writeNoteOps();
1954 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001955 }
1956
Dianne Hackborn72e39832013-01-18 18:36:09 -08001957 private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
1958 ArrayList<AppOpsManager.OpEntry> resOps = null;
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001959 final long elapsedNow = SystemClock.elapsedRealtime();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001960 if (ops == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001961 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001962 for (int j=0; j<pkgOps.size(); j++) {
1963 Op curOp = pkgOps.valueAt(j);
Svet Ganovaf189e32019-02-15 18:45:29 -08001964 resOps.add(getOpEntryForResult(curOp, elapsedNow));
Dianne Hackborn72e39832013-01-18 18:36:09 -08001965 }
1966 } else {
1967 for (int j=0; j<ops.length; j++) {
1968 Op curOp = pkgOps.get(ops[j]);
1969 if (curOp != null) {
1970 if (resOps == null) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07001971 resOps = new ArrayList<>();
Dianne Hackborn72e39832013-01-18 18:36:09 -08001972 }
Svet Ganovaf189e32019-02-15 18:45:29 -08001973 resOps.add(getOpEntryForResult(curOp, elapsedNow));
Dianne Hackborn72e39832013-01-18 18:36:09 -08001974 }
1975 }
1976 }
1977 return resOps;
1978 }
1979
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001980 @Nullable
1981 private ArrayList<AppOpsManager.OpEntry> collectUidOps(@NonNull UidState uidState,
1982 @Nullable int[] ops) {
1983 if (uidState.opModes == null) {
1984 return null;
1985 }
1986
1987 int opModeCount = uidState.opModes.size();
1988 if (opModeCount == 0) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08001989 return null;
1990 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001991 ArrayList<AppOpsManager.OpEntry> resOps = null;
1992 if (ops == null) {
1993 resOps = new ArrayList<>();
Philip P. Moltmann59076d82019-08-19 15:00:40 -07001994 for (int i = 0; i < opModeCount; i++) {
1995 int code = uidState.opModes.keyAt(i);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08001996 resOps.add(new OpEntry(code, uidState.opModes.get(code), Collections.emptyMap()));
Dianne Hackbornc7214a32017-04-11 13:32:47 -07001997 }
1998 } else {
Hai Zhang93540ca2019-09-28 00:04:18 +00001999 for (int j=0; j<ops.length; j++) {
Philip P. Moltmannf56fe2c2019-10-30 08:42:47 -07002000 int code = ops[j];
2001 if (uidState.opModes.indexOfKey(code) >= 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002002 if (resOps == null) {
2003 resOps = new ArrayList<>();
2004 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08002005 resOps.add(new OpEntry(code, uidState.opModes.get(code),
2006 Collections.emptyMap()));
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002007 }
2008 }
2009 }
2010 return resOps;
2011 }
2012
Svet Ganovaf189e32019-02-15 18:45:29 -08002013 private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, long elapsedNow) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002014 return op.createEntryLocked();
Svet Ganovaf189e32019-02-15 18:45:29 -08002015 }
2016
Dianne Hackborn35654b62013-01-14 17:38:02 -08002017 @Override
2018 public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
2019 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
2020 Binder.getCallingPid(), Binder.getCallingUid(), null);
2021 ArrayList<AppOpsManager.PackageOps> res = null;
2022 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07002023 final int uidStateCount = mUidStates.size();
2024 for (int i = 0; i < uidStateCount; i++) {
2025 UidState uidState = mUidStates.valueAt(i);
2026 if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
2027 continue;
2028 }
2029 ArrayMap<String, Ops> packages = uidState.pkgOps;
2030 final int packageCount = packages.size();
2031 for (int j = 0; j < packageCount; j++) {
2032 Ops pkgOps = packages.valueAt(j);
Dianne Hackborn72e39832013-01-18 18:36:09 -08002033 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002034 if (resOps != null) {
2035 if (res == null) {
2036 res = new ArrayList<AppOpsManager.PackageOps>();
2037 }
2038 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07002039 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002040 res.add(resPackage);
2041 }
2042 }
2043 }
2044 }
2045 return res;
2046 }
2047
2048 @Override
Dianne Hackborn72e39832013-01-18 18:36:09 -08002049 public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
2050 int[] ops) {
2051 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
2052 Binder.getCallingPid(), Binder.getCallingUid(), null);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002053 String resolvedPackageName = resolvePackageName(uid, packageName);
2054 if (resolvedPackageName == null) {
2055 return Collections.emptyList();
2056 }
Dianne Hackborn72e39832013-01-18 18:36:09 -08002057 synchronized (this) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002058 Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false /* edit */);
Dianne Hackborn72e39832013-01-18 18:36:09 -08002059 if (pkgOps == null) {
2060 return null;
2061 }
2062 ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
2063 if (resOps == null) {
2064 return null;
2065 }
2066 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
2067 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
Svet Ganov2af57082015-07-30 08:44:20 -07002068 pkgOps.packageName, pkgOps.uidState.uid, resOps);
Dianne Hackborn72e39832013-01-18 18:36:09 -08002069 res.add(resPackage);
2070 return res;
2071 }
2072 }
2073
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08002074 /**
2075 * Verify that historical appop request arguments are valid.
2076 */
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002077 private void ensureHistoricalOpRequestIsValid(int uid, String packageName,
2078 String attributionTag, List<String> opNames, int filter, long beginTimeMillis,
2079 long endTimeMillis, int flags) {
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08002080 if ((filter & FILTER_BY_UID) != 0) {
2081 Preconditions.checkArgument(uid != Process.INVALID_UID);
2082 } else {
2083 Preconditions.checkArgument(uid == Process.INVALID_UID);
2084 }
2085
2086 if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
2087 Objects.requireNonNull(packageName);
2088 } else {
2089 Preconditions.checkArgument(packageName == null);
2090 }
2091
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002092 if ((filter & FILTER_BY_ATTRIBUTION_TAG) == 0) {
2093 Preconditions.checkArgument(attributionTag == null);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08002094 }
2095
2096 if ((filter & FILTER_BY_OP_NAMES) != 0) {
2097 Objects.requireNonNull(opNames);
2098 } else {
2099 Preconditions.checkArgument(opNames == null);
2100 }
2101
2102 Preconditions.checkFlagsArgument(filter,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002103 FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_ATTRIBUTION_TAG
2104 | FILTER_BY_OP_NAMES);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08002105 Preconditions.checkArgumentNonnegative(beginTimeMillis);
2106 Preconditions.checkArgument(endTimeMillis > beginTimeMillis);
2107 Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
2108 }
2109
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002110 @Override
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002111 public void getHistoricalOps(int uid, String packageName, String attributionTag,
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08002112 List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
2113 int flags, RemoteCallback callback) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002114 ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08002115 beginTimeMillis, endTimeMillis, flags);
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002116 Objects.requireNonNull(callback, "callback cannot be null");
Svet Ganovad0a49b2018-10-29 10:07:08 -07002117
Nate Myren697650b2020-01-23 13:25:06 -08002118 ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
2119 boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
Stanislav Zholnin727e0e72020-02-11 17:45:22 +00002120 boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
Nate Myren697650b2020-01-23 13:25:06 -08002121
Stanislav Zholnin727e0e72020-02-11 17:45:22 +00002122 if (!isCallerSystem && !isCallerInstrumented) {
Nate Myren697650b2020-01-23 13:25:06 -08002123 mHandler.post(() -> callback.sendResult(new Bundle()));
2124 return;
2125 }
2126
Svet Ganovad0a49b2018-10-29 10:07:08 -07002127 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Svet Ganov8455ba22019-01-02 13:05:56 -08002128 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
Svet Ganovad0a49b2018-10-29 10:07:08 -07002129
Svet Ganov23c88db2019-01-22 20:38:11 -08002130 final String[] opNamesArray = (opNames != null)
2131 ? opNames.toArray(new String[opNames.size()]) : null;
Svet Ganovad0a49b2018-10-29 10:07:08 -07002132
Svet Ganovaf189e32019-02-15 18:45:29 -08002133 // Must not hold the appops lock
Svet Ganov73fd86e2020-01-09 20:26:14 -08002134 mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002135 mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, filter,
Svet Ganov73fd86e2020-01-09 20:26:14 -08002136 beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
Svet Ganovad0a49b2018-10-29 10:07:08 -07002137 }
2138
2139 @Override
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002140 public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08002141 List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
2142 int flags, RemoteCallback callback) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002143 ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08002144 beginTimeMillis, endTimeMillis, flags);
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002145 Objects.requireNonNull(callback, "callback cannot be null");
Svet Ganovad0a49b2018-10-29 10:07:08 -07002146
Svet Ganov8e5bf962019-03-19 23:59:03 -07002147 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
Svet Ganov8455ba22019-01-02 13:05:56 -08002148 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
Svet Ganovad0a49b2018-10-29 10:07:08 -07002149
Svet Ganov23c88db2019-01-22 20:38:11 -08002150 final String[] opNamesArray = (opNames != null)
2151 ? opNames.toArray(new String[opNames.size()]) : null;
2152
Svet Ganov8455ba22019-01-02 13:05:56 -08002153 // Must not hold the appops lock
Svet Ganov73fd86e2020-01-09 20:26:14 -08002154 mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002155 mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray,
Svet Ganov73fd86e2020-01-09 20:26:14 -08002156 filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
Svet Ganovad0a49b2018-10-29 10:07:08 -07002157 }
2158
2159 @Override
Svet Ganov8e5bf962019-03-19 23:59:03 -07002160 public void reloadNonHistoricalState() {
2161 mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
2162 Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
2163 writeState();
2164 readState();
2165 }
2166
2167 @Override
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002168 public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
2169 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
2170 Binder.getCallingPid(), Binder.getCallingUid(), null);
2171 synchronized (this) {
2172 UidState uidState = getUidStateLocked(uid, false);
2173 if (uidState == null) {
2174 return null;
2175 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002176 ArrayList<AppOpsManager.OpEntry> resOps = collectUidOps(uidState, ops);
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002177 if (resOps == null) {
2178 return null;
2179 }
Hai Zhang93540ca2019-09-28 00:04:18 +00002180 ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07002181 AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
2182 null, uidState.uid, resOps);
2183 res.add(resPackage);
2184 return res;
2185 }
2186 }
2187
Eugene Susla463d5922019-07-17 18:14:15 -07002188 private void pruneOpLocked(Op op, int uid, String packageName) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002189 op.removeAttributionsWithNoTime();
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002190
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002191 if (op.mAttributions.isEmpty()) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002192 Ops ops = getOpsLocked(uid, packageName, null, null, false /* edit */);
Dianne Hackborn607b4142013-08-02 18:10:10 -07002193 if (ops != null) {
2194 ops.remove(op.op);
2195 if (ops.size() <= 0) {
Svet Ganov2af57082015-07-30 08:44:20 -07002196 UidState uidState = ops.uidState;
2197 ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
Dianne Hackborn607b4142013-08-02 18:10:10 -07002198 if (pkgOps != null) {
2199 pkgOps.remove(ops.packageName);
Svet Ganov2af57082015-07-30 08:44:20 -07002200 if (pkgOps.isEmpty()) {
2201 uidState.pkgOps = null;
2202 }
2203 if (uidState.isDefault()) {
2204 mUidStates.remove(uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07002205 }
2206 }
2207 }
2208 }
2209 }
2210 }
2211
Svet Ganovaf189e32019-02-15 18:45:29 -08002212 private void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002213 if (callingPid == Process.myPid()) {
2214 return;
2215 }
2216 final int callingUser = UserHandle.getUserId(callingUid);
2217 synchronized (this) {
2218 if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
2219 if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
2220 // Profile owners are allowed to change modes but only for apps
2221 // within their user.
2222 return;
2223 }
2224 }
2225 }
2226 mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
2227 Binder.getCallingPid(), Binder.getCallingUid(), null);
2228 }
2229
Dianne Hackborn72e39832013-01-18 18:36:09 -08002230 @Override
Svet Ganov2af57082015-07-30 08:44:20 -07002231 public void setUidMode(int code, int uid, int mode) {
Hai Zhangf4ef0392020-02-03 14:49:35 -08002232 setUidMode(code, uid, mode, null);
2233 }
2234
2235 private void setUidMode(int code, int uid, int mode,
Hai Zhang8846aaa2020-02-13 15:19:54 -08002236 @Nullable IAppOpsCallback permissionPolicyCallback) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08002237 if (DEBUG) {
2238 Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
2239 + " by uid " + Binder.getCallingUid());
2240 }
2241
Dianne Hackbornd5254412018-05-11 18:02:58 -07002242 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Svet Ganov2af57082015-07-30 08:44:20 -07002243 verifyIncomingOp(code);
2244 code = AppOpsManager.opToSwitch(code);
2245
Hai Zhang8846aaa2020-02-13 15:19:54 -08002246 if (permissionPolicyCallback == null) {
2247 updatePermissionRevokedCompat(uid, code, mode);
2248 }
Hai Zhange53e4c52019-10-08 18:57:01 -07002249
Svet Ganov2af57082015-07-30 08:44:20 -07002250 synchronized (this) {
2251 final int defaultMode = AppOpsManager.opToDefaultMode(code);
2252
2253 UidState uidState = getUidStateLocked(uid, false);
2254 if (uidState == null) {
2255 if (mode == defaultMode) {
2256 return;
2257 }
2258 uidState = new UidState(uid);
Hai Zhang93540ca2019-09-28 00:04:18 +00002259 uidState.opModes = new SparseIntArray();
2260 uidState.opModes.put(code, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07002261 mUidStates.put(uid, uidState);
2262 scheduleWriteLocked();
Hai Zhang93540ca2019-09-28 00:04:18 +00002263 } else if (uidState.opModes == null) {
2264 if (mode != defaultMode) {
2265 uidState.opModes = new SparseIntArray();
2266 uidState.opModes.put(code, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07002267 scheduleWriteLocked();
2268 }
Hai Zhang93540ca2019-09-28 00:04:18 +00002269 } else {
2270 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
2271 return;
2272 }
2273 if (mode == defaultMode) {
2274 uidState.opModes.delete(code);
2275 if (uidState.opModes.size() <= 0) {
2276 uidState.opModes = null;
2277 }
2278 } else {
2279 uidState.opModes.put(code, mode);
2280 }
2281 scheduleWriteLocked();
Svet Ganov2af57082015-07-30 08:44:20 -07002282 }
Wei Wang711eb662019-03-21 18:24:17 -07002283 uidState.evalForegroundOps(mOpModeWatchers);
Svet Ganov2af57082015-07-30 08:44:20 -07002284 }
2285
Hai Zhang8846aaa2020-02-13 15:19:54 -08002286 notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback);
Philip P. Moltmann584c23a2020-01-24 14:21:12 -08002287 notifyOpChangedSync(code, uid, null, mode);
2288 }
2289
2290 /**
2291 * Notify that an op changed for all packages in an uid.
2292 *
2293 * @param code The op that changed
2294 * @param uid The uid the op was changed for
2295 * @param onlyForeground Only notify watchers that watch for foreground changes
2296 */
2297 private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
2298 @Nullable IAppOpsCallback callbackToIgnore) {
Svetoslav215b44a2015-08-04 19:03:40 -07002299 String[] uidPackageNames = getPackagesForUid(uid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002300 ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
Svet Ganov2af57082015-07-30 08:44:20 -07002301
riddle_hsu40b300f2015-11-23 13:22:03 +08002302 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002303 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov2af57082015-07-30 08:44:20 -07002304 if (callbacks != null) {
Svet Ganov2af57082015-07-30 08:44:20 -07002305 final int callbackCount = callbacks.size();
2306 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002307 ModeCallback callback = callbacks.valueAt(i);
Philip P. Moltmann584c23a2020-01-24 14:21:12 -08002308 if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
2309 continue;
2310 }
2311
riddle_hsu40b300f2015-11-23 13:22:03 +08002312 ArraySet<String> changedPackages = new ArraySet<>();
2313 Collections.addAll(changedPackages, uidPackageNames);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002314 if (callbackSpecs == null) {
2315 callbackSpecs = new ArrayMap<>();
2316 }
riddle_hsu40b300f2015-11-23 13:22:03 +08002317 callbackSpecs.put(callback, changedPackages);
2318 }
2319 }
2320
2321 for (String uidPackageName : uidPackageNames) {
2322 callbacks = mPackageModeWatchers.get(uidPackageName);
2323 if (callbacks != null) {
2324 if (callbackSpecs == null) {
2325 callbackSpecs = new ArrayMap<>();
Svet Ganov2af57082015-07-30 08:44:20 -07002326 }
riddle_hsu40b300f2015-11-23 13:22:03 +08002327 final int callbackCount = callbacks.size();
2328 for (int i = 0; i < callbackCount; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002329 ModeCallback callback = callbacks.valueAt(i);
Philip P. Moltmann584c23a2020-01-24 14:21:12 -08002330 if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
2331 continue;
2332 }
2333
riddle_hsu40b300f2015-11-23 13:22:03 +08002334 ArraySet<String> changedPackages = callbackSpecs.get(callback);
2335 if (changedPackages == null) {
2336 changedPackages = new ArraySet<>();
2337 callbackSpecs.put(callback, changedPackages);
2338 }
2339 changedPackages.add(uidPackageName);
2340 }
Svet Ganov2af57082015-07-30 08:44:20 -07002341 }
2342 }
Hai Zhangf4ef0392020-02-03 14:49:35 -08002343
2344 if (callbackSpecs != null && callbackToIgnore != null) {
2345 callbackSpecs.remove(mModeWatchers.get(callbackToIgnore.asBinder()));
2346 }
Svet Ganov2af57082015-07-30 08:44:20 -07002347 }
2348
2349 if (callbackSpecs == null) {
2350 return;
2351 }
2352
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002353 for (int i = 0; i < callbackSpecs.size(); i++) {
2354 final ModeCallback callback = callbackSpecs.keyAt(i);
2355 final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
2356 if (reportedPackageNames == null) {
2357 mHandler.sendMessage(PooledLambda.obtainMessage(
2358 AppOpsService::notifyOpChanged,
2359 this, callback, code, uid, (String) null));
2360
2361 } else {
2362 final int reportedPackageCount = reportedPackageNames.size();
2363 for (int j = 0; j < reportedPackageCount; j++) {
2364 final String reportedPackageName = reportedPackageNames.valueAt(j);
2365 mHandler.sendMessage(PooledLambda.obtainMessage(
2366 AppOpsService::notifyOpChanged,
2367 this, callback, code, uid, reportedPackageName));
Svet Ganov2af57082015-07-30 08:44:20 -07002368 }
2369 }
Svet Ganov2af57082015-07-30 08:44:20 -07002370 }
Sudheer Shankab1613982019-05-16 16:55:50 -07002371 }
2372
Hai Zhange53e4c52019-10-08 18:57:01 -07002373 private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
2374 PackageManager packageManager = mContext.getPackageManager();
Philip P. Moltmannfe2fc3a2020-02-05 16:59:39 -08002375 if (packageManager == null) {
2376 // This can only happen during early boot. At this time the permission state and appop
2377 // state are in sync
2378 return;
2379 }
2380
Hai Zhange53e4c52019-10-08 18:57:01 -07002381 String[] packageNames = packageManager.getPackagesForUid(uid);
2382 if (ArrayUtils.isEmpty(packageNames)) {
2383 return;
2384 }
2385 String packageName = packageNames[0];
2386
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08002387 int[] ops = mSwitchedOps.get(switchCode);
2388 for (int code : ops) {
Hai Zhange53e4c52019-10-08 18:57:01 -07002389 String permissionName = AppOpsManager.opToPermission(code);
2390 if (permissionName == null) {
2391 continue;
2392 }
2393
Hai Zhang86425532020-02-03 19:45:15 -08002394 if (packageManager.checkPermission(permissionName, packageName)
2395 != PackageManager.PERMISSION_GRANTED) {
2396 continue;
2397 }
2398
Hai Zhange53e4c52019-10-08 18:57:01 -07002399 PermissionInfo permissionInfo;
2400 try {
2401 permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
2402 } catch (PackageManager.NameNotFoundException e) {
2403 e.printStackTrace();
2404 continue;
2405 }
2406
2407 if (!permissionInfo.isRuntime()) {
2408 continue;
2409 }
2410
Hai Zhang23d30a22020-02-04 11:06:31 -08002411 PackageManagerInternal packageManagerInternal = LocalServices.getService(
2412 PackageManagerInternal.class);
2413 boolean supportsRuntimePermissions = packageManagerInternal.getUidTargetSdkVersion(uid)
2414 >= Build.VERSION_CODES.M;
2415
Hai Zhange53e4c52019-10-08 18:57:01 -07002416 UserHandle user = UserHandle.getUserHandleForUid(uid);
2417 boolean isRevokedCompat;
2418 if (permissionInfo.backgroundPermission != null) {
Hai Zhang29674dd2020-02-05 01:36:25 -08002419 if (packageManager.checkPermission(permissionInfo.backgroundPermission, packageName)
2420 == PackageManager.PERMISSION_GRANTED) {
2421 boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
Hai Zhang23d30a22020-02-04 11:06:31 -08002422
Hai Zhang29674dd2020-02-05 01:36:25 -08002423 if (isBackgroundRevokedCompat && supportsRuntimePermissions) {
2424 Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime"
2425 + " permission state, this is discouraged and you should revoke the"
2426 + " runtime permission instead: uid=" + uid + ", switchCode="
2427 + switchCode + ", mode=" + mode + ", permission="
2428 + permissionInfo.backgroundPermission);
2429 }
Hai Zhang23d30a22020-02-04 11:06:31 -08002430
Hai Zhang29674dd2020-02-05 01:36:25 -08002431 long identity = Binder.clearCallingIdentity();
2432 try {
2433 packageManager.updatePermissionFlags(permissionInfo.backgroundPermission,
2434 packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
2435 isBackgroundRevokedCompat
2436 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
2437 } finally {
2438 Binder.restoreCallingIdentity(identity);
2439 }
Hai Zhange53e4c52019-10-08 18:57:01 -07002440 }
2441
2442 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED
2443 && mode != AppOpsManager.MODE_FOREGROUND;
2444 } else {
2445 isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
2446 }
2447
Hai Zhang23d30a22020-02-04 11:06:31 -08002448 if (isRevokedCompat && supportsRuntimePermissions) {
2449 Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime"
2450 + " permission state, this is discouraged and you should revoke the"
2451 + " runtime permission instead: uid=" + uid + ", switchCode="
2452 + switchCode + ", mode=" + mode + ", permission=" + permissionName);
2453 }
2454
Hai Zhange53e4c52019-10-08 18:57:01 -07002455 long identity = Binder.clearCallingIdentity();
2456 try {
2457 packageManager.updatePermissionFlags(permissionName, packageName,
2458 PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat
2459 ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
2460 } finally {
2461 Binder.restoreCallingIdentity(identity);
2462 }
2463 }
2464 }
2465
Sudheer Shankab1613982019-05-16 16:55:50 -07002466 private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) {
2467 final StorageManagerInternal storageManagerInternal =
2468 LocalServices.getService(StorageManagerInternal.class);
2469 if (storageManagerInternal != null) {
2470 storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode);
2471 }
Svet Ganov2af57082015-07-30 08:44:20 -07002472 }
2473
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002474 /**
2475 * Sets the mode for a certain op and uid.
2476 *
2477 * @param code The op code to set
2478 * @param uid The UID for which to set
2479 * @param packageName The package for which to set
2480 * @param mode The new mode to set
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07002481 */
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002482 @Override
2483 public void setMode(int code, int uid, @NonNull String packageName, int mode) {
Hai Zhangf4ef0392020-02-03 14:49:35 -08002484 setMode(code, uid, packageName, mode, null);
2485 }
2486
2487 private void setMode(int code, int uid, @NonNull String packageName, int mode,
Hai Zhang8846aaa2020-02-13 15:19:54 -08002488 @Nullable IAppOpsCallback permissionPolicyCallback) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002489 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08002490 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002491 ArraySet<ModeCallback> repCbs = null;
Dianne Hackbornc2293022013-02-06 23:14:49 -08002492 code = AppOpsManager.opToSwitch(code);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002493
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002494 RestrictionBypass bypass;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002495 try {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002496 bypass = verifyAndGetBypass(uid, packageName, null);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002497 } catch (SecurityException e) {
2498 Slog.e(TAG, "Cannot setMode", e);
2499 return;
2500 }
2501
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002502 synchronized (this) {
Svet Ganov2af57082015-07-30 08:44:20 -07002503 UidState uidState = getUidStateLocked(uid, false);
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002504 Op op = getOpLocked(code, uid, packageName, null, bypass, true);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002505 if (op != null) {
2506 if (op.mode != mode) {
2507 op.mode = mode;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002508 if (uidState != null) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002509 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002510 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002511 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002512 if (cbs != null) {
2513 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002514 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002515 }
2516 repCbs.addAll(cbs);
2517 }
2518 cbs = mPackageModeWatchers.get(packageName);
2519 if (cbs != null) {
2520 if (repCbs == null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002521 repCbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002522 }
2523 repCbs.addAll(cbs);
2524 }
Hai Zhang8846aaa2020-02-13 15:19:54 -08002525 if (repCbs != null && permissionPolicyCallback != null) {
2526 repCbs.remove(mModeWatchers.get(permissionPolicyCallback.asBinder()));
Hai Zhangf4ef0392020-02-03 14:49:35 -08002527 }
David Braunf5d83192013-09-16 13:43:51 -07002528 if (mode == AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborn514074f2013-02-11 10:52:46 -08002529 // If going into the default mode, prune this op
2530 // if there is nothing else interesting in it.
Eugene Susla463d5922019-07-17 18:14:15 -07002531 pruneOpLocked(op, uid, packageName);
Dianne Hackborn514074f2013-02-11 10:52:46 -08002532 }
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002533 scheduleFastWriteLocked();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002534 }
2535 }
2536 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08002537 if (repCbs != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002538 mHandler.sendMessage(PooledLambda.obtainMessage(
2539 AppOpsService::notifyOpChanged,
2540 this, repCbs, code, uid, packageName));
Dianne Hackbornc2293022013-02-06 23:14:49 -08002541 }
Sudheer Shankab1613982019-05-16 16:55:50 -07002542
2543 notifyOpChangedSync(code, uid, packageName, mode);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002544 }
2545
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002546 private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
2547 int uid, String packageName) {
2548 for (int i = 0; i < callbacks.size(); i++) {
2549 final ModeCallback callback = callbacks.valueAt(i);
2550 notifyOpChanged(callback, code, uid, packageName);
2551 }
2552 }
2553
2554 private void notifyOpChanged(ModeCallback callback, int code,
2555 int uid, String packageName) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002556 if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002557 return;
2558 }
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08002559
2560 // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
2561 int[] switchedCodes;
2562 if (callback.mWatchedOpCode == ALL_OPS) {
2563 switchedCodes = mSwitchedOps.get(code);
2564 } else if (callback.mWatchedOpCode == OP_NONE) {
2565 switchedCodes = new int[]{code};
2566 } else {
2567 switchedCodes = new int[]{callback.mWatchedOpCode};
2568 }
2569
2570 for (int switchedCode : switchedCodes) {
2571 // There are features watching for mode changes such as window manager
2572 // and location manager which are in our process. The callbacks in these
2573 // features may require permissions our remote caller does not have.
2574 final long identity = Binder.clearCallingIdentity();
2575 try {
2576 callback.mCallback.opChanged(switchedCode, uid, packageName);
2577 } catch (RemoteException e) {
2578 /* ignore */
2579 } finally {
2580 Binder.restoreCallingIdentity(identity);
2581 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002582 }
2583 }
2584
2585 private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
2586 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
2587 int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07002588 if (cbs == null) {
2589 return callbacks;
2590 }
2591 if (callbacks == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002592 callbacks = new HashMap<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002593 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08002594 final int N = cbs.size();
2595 for (int i=0; i<N; i++) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002596 ModeCallback cb = cbs.valueAt(i);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002597 ArrayList<ChangeRec> reports = callbacks.get(cb);
Narayan Kamath1dfc1ab2020-05-01 15:17:03 +01002598 boolean duplicate = false;
Dianne Hackborn607b4142013-08-02 18:10:10 -07002599 if (reports == null) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002600 reports = new ArrayList<>();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002601 callbacks.put(cb, reports);
Svet Ganov2af57082015-07-30 08:44:20 -07002602 } else {
2603 final int reportCount = reports.size();
2604 for (int j = 0; j < reportCount; j++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002605 ChangeRec report = reports.get(j);
2606 if (report.op == op && report.pkg.equals(packageName)) {
Svet Ganov2af57082015-07-30 08:44:20 -07002607 duplicate = true;
2608 break;
2609 }
2610 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002611 }
Svet Ganov2af57082015-07-30 08:44:20 -07002612 if (!duplicate) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002613 reports.add(new ChangeRec(op, uid, packageName));
Svet Ganov2af57082015-07-30 08:44:20 -07002614 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002615 }
2616 return callbacks;
2617 }
2618
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002619 static final class ChangeRec {
2620 final int op;
2621 final int uid;
2622 final String pkg;
2623
2624 ChangeRec(int _op, int _uid, String _pkg) {
2625 op = _op;
2626 uid = _uid;
2627 pkg = _pkg;
2628 }
2629 }
2630
Dianne Hackborn607b4142013-08-02 18:10:10 -07002631 @Override
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002632 public void resetAllModes(int reqUserId, String reqPackageName) {
2633 final int callingPid = Binder.getCallingPid();
2634 final int callingUid = Binder.getCallingUid();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002635 reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
2636 true, true, "resetAllModes", null);
Svet Ganov2af57082015-07-30 08:44:20 -07002637
2638 int reqUid = -1;
2639 if (reqPackageName != null) {
2640 try {
2641 reqUid = AppGlobals.getPackageManager().getPackageUid(
Jeff Sharkeycd654482016-01-08 17:42:11 -07002642 reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
Svet Ganov2af57082015-07-30 08:44:20 -07002643 } catch (RemoteException e) {
2644 /* ignore - local call */
2645 }
2646 }
2647
Dianne Hackbornd5254412018-05-11 18:02:58 -07002648 enforceManageAppOpsModes(callingPid, callingUid, reqUid);
2649
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002650 HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
Dianne Hackborn607b4142013-08-02 18:10:10 -07002651 synchronized (this) {
2652 boolean changed = false;
Svet Ganov2af57082015-07-30 08:44:20 -07002653 for (int i = mUidStates.size() - 1; i >= 0; i--) {
2654 UidState uidState = mUidStates.valueAt(i);
2655
Hai Zhang93540ca2019-09-28 00:04:18 +00002656 SparseIntArray opModes = uidState.opModes;
2657 if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
2658 final int uidOpCount = opModes.size();
2659 for (int j = uidOpCount - 1; j >= 0; j--) {
2660 final int code = opModes.keyAt(j);
Svet Ganov2af57082015-07-30 08:44:20 -07002661 if (AppOpsManager.opAllowsReset(code)) {
Hai Zhang93540ca2019-09-28 00:04:18 +00002662 opModes.removeAt(j);
2663 if (opModes.size() <= 0) {
2664 uidState.opModes = null;
2665 }
Svet Ganov2af57082015-07-30 08:44:20 -07002666 for (String packageName : getPackagesForUid(uidState.uid)) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002667 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07002668 mOpModeWatchers.get(code));
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002669 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
Svet Ganov2af57082015-07-30 08:44:20 -07002670 mPackageModeWatchers.get(packageName));
2671 }
2672 }
2673 }
2674 }
2675
2676 if (uidState.pkgOps == null) {
2677 continue;
2678 }
2679
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002680 if (reqUserId != UserHandle.USER_ALL
Svet Ganov2af57082015-07-30 08:44:20 -07002681 && reqUserId != UserHandle.getUserId(uidState.uid)) {
Alexandra Gherghinad6a98972014-08-04 17:05:34 +01002682 // Skip any ops for a different user
2683 continue;
2684 }
Svet Ganov2af57082015-07-30 08:44:20 -07002685
2686 Map<String, Ops> packages = uidState.pkgOps;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002687 Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002688 boolean uidChanged = false;
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002689 while (it.hasNext()) {
2690 Map.Entry<String, Ops> ent = it.next();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002691 String packageName = ent.getKey();
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002692 if (reqPackageName != null && !reqPackageName.equals(packageName)) {
2693 // Skip any ops for a different package
2694 continue;
2695 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002696 Ops pkgOps = ent.getValue();
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002697 for (int j=pkgOps.size()-1; j>=0; j--) {
Dianne Hackborn607b4142013-08-02 18:10:10 -07002698 Op curOp = pkgOps.valueAt(j);
Dianne Hackborn8828d3a2013-09-25 16:47:10 -07002699 if (AppOpsManager.opAllowsReset(curOp.op)
2700 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
David Braunf5d83192013-09-16 13:43:51 -07002701 curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
Dianne Hackborn607b4142013-08-02 18:10:10 -07002702 changed = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002703 uidChanged = true;
Svet Ganovaf189e32019-02-15 18:45:29 -08002704 final int uid = curOp.uidState.uid;
2705 callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07002706 mOpModeWatchers.get(curOp.op));
Svet Ganovaf189e32019-02-15 18:45:29 -08002707 callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
Dianne Hackborn607b4142013-08-02 18:10:10 -07002708 mPackageModeWatchers.get(packageName));
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002709
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002710 curOp.removeAttributionsWithNoTime();
2711 if (curOp.mAttributions.isEmpty()) {
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002712 pkgOps.removeAt(j);
2713 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002714 }
2715 }
Dianne Hackborn7f09ec32013-08-07 15:36:08 -07002716 if (pkgOps.size() == 0) {
2717 it.remove();
2718 }
2719 }
Svet Ganov2af57082015-07-30 08:44:20 -07002720 if (uidState.isDefault()) {
2721 mUidStates.remove(uidState.uid);
Dianne Hackborn607b4142013-08-02 18:10:10 -07002722 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002723 if (uidChanged) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002724 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07002725 }
Dianne Hackborn607b4142013-08-02 18:10:10 -07002726 }
Svet Ganov2af57082015-07-30 08:44:20 -07002727
Dianne Hackborn607b4142013-08-02 18:10:10 -07002728 if (changed) {
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08002729 scheduleFastWriteLocked();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002730 }
2731 }
2732 if (callbacks != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002733 for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
2734 ModeCallback cb = ent.getKey();
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002735 ArrayList<ChangeRec> reports = ent.getValue();
Dianne Hackborn607b4142013-08-02 18:10:10 -07002736 for (int i=0; i<reports.size(); i++) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07002737 ChangeRec rep = reports.get(i);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002738 mHandler.sendMessage(PooledLambda.obtainMessage(
2739 AppOpsService::notifyOpChanged,
2740 this, cb, rep.op, rep.uid, rep.pkg));
Dianne Hackborn607b4142013-08-02 18:10:10 -07002741 }
2742 }
2743 }
2744 }
2745
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002746 private void evalAllForegroundOpsLocked() {
2747 for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
2748 final UidState uidState = mUidStates.valueAt(uidi);
2749 if (uidState.foregroundOps != null) {
2750 uidState.evalForegroundOps(mOpModeWatchers);
2751 }
2752 }
2753 }
2754
Dianne Hackbornc2293022013-02-06 23:14:49 -08002755 @Override
2756 public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002757 startWatchingModeWithFlags(op, packageName, 0, callback);
2758 }
2759
2760 @Override
2761 public void startWatchingModeWithFlags(int op, String packageName, int flags,
2762 IAppOpsCallback callback) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002763 int watchedUid = -1;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07002764 final int callingUid = Binder.getCallingUid();
2765 final int callingPid = Binder.getCallingPid();
Dianne Hackborn5376edd2018-06-05 13:21:16 -07002766 // TODO: should have a privileged permission to protect this.
2767 // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
2768 // the USAGE_STATS permission since this can provide information about when an
2769 // app is in the foreground?
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002770 Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
2771 AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
Svetoslav Ganov8de59712015-12-09 18:25:13 -08002772 if (callback == null) {
2773 return;
2774 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08002775 synchronized (this) {
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08002776 int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
2777
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08002778 int notifiedOps;
Philip P. Moltmann7641cd02020-03-11 14:42:43 -07002779 if ((flags & CALL_BACK_ON_SWITCHED_OP) == 0) {
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08002780 if (op == OP_NONE) {
2781 notifiedOps = ALL_OPS;
2782 } else {
2783 notifiedOps = op;
2784 }
2785 } else {
2786 notifiedOps = switchOp;
2787 }
2788
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002789 ModeCallback cb = mModeWatchers.get(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08002790 if (cb == null) {
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08002791 cb = new ModeCallback(callback, watchedUid, flags, notifiedOps, callingUid,
2792 callingPid);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002793 mModeWatchers.put(callback.asBinder(), cb);
2794 }
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08002795 if (switchOp != AppOpsManager.OP_NONE) {
2796 ArraySet<ModeCallback> cbs = mOpModeWatchers.get(switchOp);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002797 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08002798 cbs = new ArraySet<>();
Philip P. Moltmannb2bc6512020-01-24 15:34:34 -08002799 mOpModeWatchers.put(switchOp, cbs);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002800 }
2801 cbs.add(cb);
2802 }
2803 if (packageName != null) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002804 ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002805 if (cbs == null) {
Dianne Hackborn68d76552017-02-27 15:32:03 -08002806 cbs = new ArraySet<>();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002807 mPackageModeWatchers.put(packageName, cbs);
2808 }
2809 cbs.add(cb);
2810 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002811 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002812 }
2813 }
2814
2815 @Override
2816 public void stopWatchingMode(IAppOpsCallback callback) {
Svetoslav Ganov8de59712015-12-09 18:25:13 -08002817 if (callback == null) {
2818 return;
2819 }
Dianne Hackbornc2293022013-02-06 23:14:49 -08002820 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002821 ModeCallback cb = mModeWatchers.remove(callback.asBinder());
Dianne Hackbornc2293022013-02-06 23:14:49 -08002822 if (cb != null) {
2823 cb.unlinkToDeath();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002824 for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002825 ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002826 cbs.remove(cb);
2827 if (cbs.size() <= 0) {
2828 mOpModeWatchers.removeAt(i);
2829 }
2830 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002831 for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002832 ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002833 cbs.remove(cb);
2834 if (cbs.size() <= 0) {
2835 mPackageModeWatchers.removeAt(i);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002836 }
2837 }
2838 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07002839 evalAllForegroundOpsLocked();
Dianne Hackbornc2293022013-02-06 23:14:49 -08002840 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002841 }
2842
Svet Ganovd873ae62018-06-25 16:39:23 -07002843 public CheckOpsDelegate getAppOpsServiceDelegate() {
2844 synchronized (this) {
2845 return mCheckOpsDelegate;
2846 }
2847 }
2848
2849 public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
2850 synchronized (this) {
2851 mCheckOpsDelegate = delegate;
2852 }
2853 }
2854
Dianne Hackborne98f5db2013-07-17 17:23:25 -07002855 @Override
Svet Ganov9d528a12018-12-19 17:23:11 -08002856 public int checkOperationRaw(int code, int uid, String packageName) {
2857 return checkOperationInternal(code, uid, packageName, true /*raw*/);
2858 }
2859
2860 @Override
Dianne Hackborn35654b62013-01-14 17:38:02 -08002861 public int checkOperation(int code, int uid, String packageName) {
Svet Ganov9d528a12018-12-19 17:23:11 -08002862 return checkOperationInternal(code, uid, packageName, false /*raw*/);
2863 }
2864
2865 private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002866 final CheckOpsDelegate delegate;
Dianne Hackborn35654b62013-01-14 17:38:02 -08002867 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002868 delegate = mCheckOpsDelegate;
2869 }
Todd Kennedy556efba2018-11-15 07:43:55 -08002870 if (delegate == null) {
Svet Ganov9d528a12018-12-19 17:23:11 -08002871 return checkOperationImpl(code, uid, packageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08002872 }
Svet Ganov9d528a12018-12-19 17:23:11 -08002873 return delegate.checkOperation(code, uid, packageName, raw,
Svet Ganovd873ae62018-06-25 16:39:23 -07002874 AppOpsService.this::checkOperationImpl);
2875 }
2876
Svet Ganov9d528a12018-12-19 17:23:11 -08002877 private int checkOperationImpl(int code, int uid, String packageName,
2878 boolean raw) {
Todd Kennedy556efba2018-11-15 07:43:55 -08002879 verifyIncomingOp(code);
2880 String resolvedPackageName = resolvePackageName(uid, packageName);
2881 if (resolvedPackageName == null) {
2882 return AppOpsManager.MODE_IGNORED;
2883 }
Svet Ganov9d528a12018-12-19 17:23:11 -08002884 return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
Todd Kennedy556efba2018-11-15 07:43:55 -08002885 }
2886
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002887 /**
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002888 * Get the mode of an app-op.
2889 *
2890 * @param code The code of the op
2891 * @param uid The uid of the package the op belongs to
2892 * @param packageName The package the op belongs to
2893 * @param raw If the raw state of eval-ed state should be checked.
Philip P. Moltmann724150d2019-03-11 17:01:05 -07002894 *
2895 * @return The mode of the op
2896 */
2897 private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
Philip P. Moltmannd4ab19e2019-05-07 08:57:35 -07002898 boolean raw) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002899 RestrictionBypass bypass;
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07002900 try {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002901 bypass = verifyAndGetBypass(uid, packageName, null);
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07002902 } catch (SecurityException e) {
2903 Slog.e(TAG, "checkOperation", e);
2904 return AppOpsManager.opToDefaultMode(code);
2905 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002906
Suprabh Shukla7e017922019-08-05 17:13:23 -07002907 if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
2908 return AppOpsManager.MODE_IGNORED;
2909 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002910 synchronized (this) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002911 if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
Jason Monk62062992014-05-06 09:55:28 -04002912 return AppOpsManager.MODE_IGNORED;
2913 }
Svet Ganov2af57082015-07-30 08:44:20 -07002914 code = AppOpsManager.opToSwitch(code);
2915 UidState uidState = getUidStateLocked(uid, false);
Hai Zhang93540ca2019-09-28 00:04:18 +00002916 if (uidState != null && uidState.opModes != null
2917 && uidState.opModes.indexOfKey(code) >= 0) {
2918 final int rawMode = uidState.opModes.get(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08002919 return raw ? rawMode : uidState.evalMode(code, rawMode);
Svet Ganov2af57082015-07-30 08:44:20 -07002920 }
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002921 Op op = getOpLocked(code, uid, packageName, null, bypass, false);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002922 if (op == null) {
David Braunf5d83192013-09-16 13:43:51 -07002923 return AppOpsManager.opToDefaultMode(code);
Dianne Hackborn35654b62013-01-14 17:38:02 -08002924 }
Svet Ganovaf189e32019-02-15 18:45:29 -08002925 return raw ? op.mode : op.evalMode();
Dianne Hackborn35654b62013-01-14 17:38:02 -08002926 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002927 }
2928
2929 @Override
John Spurlock7b414672014-07-18 13:02:39 -04002930 public int checkAudioOperation(int code, int usage, int uid, String packageName) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002931 final CheckOpsDelegate delegate;
John Spurlock1af30c72014-03-10 08:33:35 -04002932 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002933 delegate = mCheckOpsDelegate;
2934 }
Todd Kennedy556efba2018-11-15 07:43:55 -08002935 if (delegate == null) {
2936 return checkAudioOperationImpl(code, usage, uid, packageName);
2937 }
Svet Ganovd873ae62018-06-25 16:39:23 -07002938 return delegate.checkAudioOperation(code, usage, uid, packageName,
2939 AppOpsService.this::checkAudioOperationImpl);
2940 }
2941
2942 private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002943 final int mode = mAudioRestrictionManager.checkAudioOperation(
2944 code, usage, uid, packageName);
2945 if (mode != AppOpsManager.MODE_ALLOWED) {
2946 return mode;
John Spurlock1af30c72014-03-10 08:33:35 -04002947 }
2948 return checkOperation(code, uid, packageName);
2949 }
2950
John Spurlock1af30c72014-03-10 08:33:35 -04002951 @Override
John Spurlock7b414672014-07-18 13:02:39 -04002952 public void setAudioRestriction(int code, int usage, int uid, int mode,
John Spurlock1af30c72014-03-10 08:33:35 -04002953 String[] exceptionPackages) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07002954 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
John Spurlock1af30c72014-03-10 08:33:35 -04002955 verifyIncomingUid(uid);
2956 verifyIncomingOp(code);
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002957
2958 mAudioRestrictionManager.setZenModeAudioRestriction(
2959 code, usage, uid, mode, exceptionPackages);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08002960
2961 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07002962 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
John Spurlock1af30c72014-03-10 08:33:35 -04002963 }
2964
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07002965
2966 @Override
2967 public void setCameraAudioRestriction(@CAMERA_AUDIO_RESTRICTION int mode) {
2968 enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), -1);
2969
2970 mAudioRestrictionManager.setCameraAudioRestriction(mode);
2971
2972 mHandler.sendMessage(PooledLambda.obtainMessage(
2973 AppOpsService::notifyWatchersOfChange, this,
2974 AppOpsManager.OP_PLAY_AUDIO, UID_ANY));
2975 mHandler.sendMessage(PooledLambda.obtainMessage(
2976 AppOpsService::notifyWatchersOfChange, this,
2977 AppOpsManager.OP_VIBRATE, UID_ANY));
2978 }
2979
John Spurlock1af30c72014-03-10 08:33:35 -04002980 @Override
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002981 public int checkPackage(int uid, String packageName) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00002982 Objects.requireNonNull(packageName);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002983 try {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07002984 verifyAndGetBypass(uid, packageName, null);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07002985
2986 return AppOpsManager.MODE_ALLOWED;
2987 } catch (SecurityException ignored) {
2988 return AppOpsManager.MODE_ERRORED;
Jeff Sharkey911d7f42013-09-05 18:11:45 -07002989 }
2990 }
2991
2992 @Override
Philip P. Moltmann59076d82019-08-19 15:00:40 -07002993 public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08002994 String proxiedAttributionTag, int proxyUid, String proxyPackageName,
2995 String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message) {
Svet Ganovd873ae62018-06-25 16:39:23 -07002996 verifyIncomingUid(proxyUid);
Svet Ganov99b60432015-06-27 13:15:22 -07002997 verifyIncomingOp(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08002998
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00002999 String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
3000 if (resolveProxyPackageName == null) {
3001 return AppOpsManager.MODE_IGNORED;
3002 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003003
3004 final boolean isProxyTrusted = mContext.checkPermission(
3005 Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
3006 == PackageManager.PERMISSION_GRANTED;
3007
3008 final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
3009 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003010 final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003011 proxyAttributionTag, Process.INVALID_UID, null, null, proxyFlags,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003012 !isProxyTrusted, "proxy " + message);
Svet Ganov99b60432015-06-27 13:15:22 -07003013 if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
3014 return proxyMode;
3015 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003016
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003017 String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
3018 if (resolveProxiedPackageName == null) {
3019 return AppOpsManager.MODE_IGNORED;
3020 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003021 final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
3022 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003023 return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003024 proxiedAttributionTag, proxyUid, resolveProxyPackageName, proxyAttributionTag,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003025 proxiedFlags, shouldCollectAsyncNotedOp, message);
Svet Ganov99b60432015-06-27 13:15:22 -07003026 }
3027
3028 @Override
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003029 public int noteOperation(int code, int uid, String packageName, String attributionTag,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003030 boolean shouldCollectAsyncNotedOp, String message) {
Svet Ganovd873ae62018-06-25 16:39:23 -07003031 final CheckOpsDelegate delegate;
3032 synchronized (this) {
Svet Ganovd873ae62018-06-25 16:39:23 -07003033 delegate = mCheckOpsDelegate;
3034 }
Todd Kennedy556efba2018-11-15 07:43:55 -08003035 if (delegate == null) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003036 return noteOperationImpl(code, uid, packageName, attributionTag,
3037 shouldCollectAsyncNotedOp, message);
Todd Kennedy556efba2018-11-15 07:43:55 -08003038 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003039 return delegate.noteOperation(code, uid, packageName, attributionTag,
3040 shouldCollectAsyncNotedOp, message, AppOpsService.this::noteOperationImpl);
Svet Ganovd873ae62018-06-25 16:39:23 -07003041 }
3042
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003043 private int noteOperationImpl(int code, int uid, @Nullable String packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003044 @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003045 @Nullable String message) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003046 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08003047 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003048 String resolvedPackageName = resolvePackageName(uid, packageName);
3049 if (resolvedPackageName == null) {
3050 return AppOpsManager.MODE_IGNORED;
3051 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003052 return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003053 Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF,
3054 shouldCollectAsyncNotedOp, message);
Svet Ganov99b60432015-06-27 13:15:22 -07003055 }
3056
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003057 private int noteOperationUnchecked(int code, int uid, @NonNull String packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003058 @Nullable String attributionTag, int proxyUid, String proxyPackageName,
3059 @Nullable String proxyAttributionTag, @OpFlags int flags,
3060 boolean shouldCollectAsyncNotedOp, @Nullable String message) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003061 RestrictionBypass bypass;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003062 try {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003063 bypass = verifyAndGetBypass(uid, packageName, attributionTag);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003064 } catch (SecurityException e) {
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07003065 Slog.e(TAG, "noteOperation", e);
3066 return AppOpsManager.MODE_ERRORED;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003067 }
3068
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003069 synchronized (this) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003070 final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass,
3071 true /* edit */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003072 if (ops == null) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003073 scheduleOpNotedIfNeededLocked(code, uid, packageName,
3074 AppOpsManager.MODE_IGNORED);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003075 if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003076 + " package " + packageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07003077 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003078 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003079 final Op op = getOpLocked(ops, code, uid, true);
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003080 if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003081 scheduleOpNotedIfNeededLocked(code, uid, packageName,
3082 AppOpsManager.MODE_IGNORED);
Jason Monk62062992014-05-06 09:55:28 -04003083 return AppOpsManager.MODE_IGNORED;
3084 }
Adam Bookatz182862e2020-04-27 21:58:22 -07003085 final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003086 if (attributedOp.isRunning()) {
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003087 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
3088 + code + " startTime of in progress event="
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003089 + attributedOp.mInProgressEvents.valueAt(0).getStartTime());
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003090 }
Svet Ganovaf189e32019-02-15 18:45:29 -08003091
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003092 final int switchCode = AppOpsManager.opToSwitch(code);
Adam Bookatz182862e2020-04-27 21:58:22 -07003093 final UidState uidState = ops.uidState;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07003094 // If there is a non-default per UID policy (we set UID op mode only if
3095 // non-default) it takes over, otherwise use the per package policy.
Hai Zhang93540ca2019-09-28 00:04:18 +00003096 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
3097 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
Svet Ganov2af57082015-07-30 08:44:20 -07003098 if (uidMode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003099 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07003100 + switchCode + " (" + code + ") uid " + uid + " package "
3101 + packageName);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003102 attributedOp.rejected(uidState.state, flags);
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003103 scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
Svet Ganov2af57082015-07-30 08:44:20 -07003104 return uidMode;
3105 }
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07003106 } else {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003107 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
3108 : op;
Svet Ganovaf189e32019-02-15 18:45:29 -08003109 final int mode = switchOp.evalMode();
Philip P. Moltmann721c9682019-12-20 11:41:46 -08003110 if (mode != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003111 if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07003112 + switchCode + " (" + code + ") uid " + uid + " package "
3113 + packageName);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003114 attributedOp.rejected(uidState.state, flags);
Svet Ganovaf189e32019-02-15 18:45:29 -08003115 scheduleOpNotedIfNeededLocked(code, uid, packageName, mode);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003116 return mode;
Svetoslav Ganov1984bba2016-04-05 13:39:25 -07003117 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003118 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003119 if (DEBUG) {
3120 Slog.d(TAG,
3121 "noteOperation: allowing code " + code + " uid " + uid + " package "
3122 + packageName + (attributionTag == null ? ""
3123 : "." + attributionTag));
3124 }
Adam Bookatz182862e2020-04-27 21:58:22 -07003125 scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003126 attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, uidState.state,
3127 flags);
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003128
3129 if (shouldCollectAsyncNotedOp) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003130 collectAsyncNotedOp(uid, packageName, code, attributionTag, message);
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003131 }
3132
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003133 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003134 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003135 }
3136
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003137 // TODO moltmann: Allow watching for attribution ops
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003138 @Override
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003139 public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
Adam Bookatz182862e2020-04-27 21:58:22 -07003140 int watchedUid = Process.INVALID_UID;
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003141 final int callingUid = Binder.getCallingUid();
3142 final int callingPid = Binder.getCallingPid();
Svet Ganovf7b47252018-02-26 11:11:27 -08003143 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3144 != PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003145 watchedUid = callingUid;
Svet Ganovf7b47252018-02-26 11:11:27 -08003146 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003147 if (ops != null) {
3148 Preconditions.checkArrayElementsInRange(ops, 0,
3149 AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
3150 }
3151 if (callback == null) {
3152 return;
3153 }
3154 synchronized (this) {
3155 SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
3156 if (callbacks == null) {
3157 callbacks = new SparseArray<>();
3158 mActiveWatchers.put(callback.asBinder(), callbacks);
3159 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003160 final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
3161 callingUid, callingPid);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003162 for (int op : ops) {
3163 callbacks.put(op, activeCallback);
3164 }
3165 }
3166 }
3167
3168 @Override
3169 public void stopWatchingActive(IAppOpsActiveCallback callback) {
3170 if (callback == null) {
3171 return;
3172 }
3173 synchronized (this) {
3174 final SparseArray<ActiveCallback> activeCallbacks =
3175 mActiveWatchers.remove(callback.asBinder());
3176 if (activeCallbacks == null) {
3177 return;
3178 }
3179 final int callbackCount = activeCallbacks.size();
3180 for (int i = 0; i < callbackCount; i++) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003181 activeCallbacks.valueAt(i).destroy();
3182 }
3183 }
3184 }
3185
3186 @Override
Adam Bookatz182862e2020-04-27 21:58:22 -07003187 public void startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback) {
3188 int watchedUid = Process.INVALID_UID;
3189 final int callingUid = Binder.getCallingUid();
3190 final int callingPid = Binder.getCallingPid();
3191 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3192 != PackageManager.PERMISSION_GRANTED) {
3193 watchedUid = callingUid;
3194 }
3195
3196 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
3197 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
3198 "Invalid op code in: " + Arrays.toString(ops));
3199 Objects.requireNonNull(callback, "Callback cannot be null");
3200
3201 synchronized (this) {
3202 SparseArray<StartedCallback> callbacks = mStartedWatchers.get(callback.asBinder());
3203 if (callbacks == null) {
3204 callbacks = new SparseArray<>();
3205 mStartedWatchers.put(callback.asBinder(), callbacks);
3206 }
3207
3208 final StartedCallback startedCallback = new StartedCallback(callback, watchedUid,
3209 callingUid, callingPid);
3210 for (int op : ops) {
3211 callbacks.put(op, startedCallback);
3212 }
3213 }
3214 }
3215
3216 @Override
3217 public void stopWatchingStarted(IAppOpsStartedCallback callback) {
3218 Objects.requireNonNull(callback, "Callback cannot be null");
3219
3220 synchronized (this) {
3221 final SparseArray<StartedCallback> startedCallbacks =
3222 mStartedWatchers.remove(callback.asBinder());
3223 if (startedCallbacks == null) {
3224 return;
3225 }
3226
3227 final int callbackCount = startedCallbacks.size();
3228 for (int i = 0; i < callbackCount; i++) {
3229 startedCallbacks.valueAt(i).destroy();
3230 }
3231 }
3232 }
3233
3234 @Override
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003235 public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
3236 int watchedUid = Process.INVALID_UID;
3237 final int callingUid = Binder.getCallingUid();
3238 final int callingPid = Binder.getCallingPid();
3239 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
3240 != PackageManager.PERMISSION_GRANTED) {
3241 watchedUid = callingUid;
3242 }
3243 Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
3244 Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
3245 "Invalid op code in: " + Arrays.toString(ops));
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00003246 Objects.requireNonNull(callback, "Callback cannot be null");
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003247 synchronized (this) {
3248 SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
3249 if (callbacks == null) {
3250 callbacks = new SparseArray<>();
3251 mNotedWatchers.put(callback.asBinder(), callbacks);
3252 }
3253 final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
3254 callingUid, callingPid);
3255 for (int op : ops) {
3256 callbacks.put(op, notedCallback);
3257 }
3258 }
3259 }
3260
3261 @Override
3262 public void stopWatchingNoted(IAppOpsNotedCallback callback) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00003263 Objects.requireNonNull(callback, "Callback cannot be null");
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003264 synchronized (this) {
3265 final SparseArray<NotedCallback> notedCallbacks =
3266 mNotedWatchers.remove(callback.asBinder());
3267 if (notedCallbacks == null) {
3268 return;
3269 }
3270 final int callbackCount = notedCallbacks.size();
3271 for (int i = 0; i < callbackCount; i++) {
3272 notedCallbacks.valueAt(i).destroy();
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003273 }
3274 }
3275 }
3276
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003277 /**
3278 * Collect an {@link AsyncNotedAppOp}.
3279 *
3280 * @param uid The uid the op was noted for
3281 * @param packageName The package the op was noted for
3282 * @param opCode The code of the op noted
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003283 * @param attributionTag attribution tag the op was noted for
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003284 * @param message The message for the op noting
3285 */
3286 private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003287 @Nullable String attributionTag, @NonNull String message) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00003288 Objects.requireNonNull(message);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003289
3290 int callingUid = Binder.getCallingUid();
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003291
3292 long token = Binder.clearCallingIdentity();
3293 try {
3294 synchronized (this) {
3295 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
3296
3297 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
3298 AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003299 attributionTag, message, System.currentTimeMillis());
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003300 final boolean[] wasNoteForwarded = {false};
3301
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003302 reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, attributionTag,
Stanislav Zholnin90516b92020-01-20 14:03:06 +00003303 message);
3304
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003305 if (callbacks != null) {
3306 callbacks.broadcast((cb) -> {
3307 try {
3308 cb.opNoted(asyncNotedOp);
3309 wasNoteForwarded[0] = true;
3310 } catch (RemoteException e) {
3311 Slog.e(TAG,
3312 "Could not forward noteOp of " + opCode + " to " + packageName
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003313 + "/" + uid + "(" + attributionTag + ")", e);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003314 }
3315 });
3316 }
3317
3318 if (!wasNoteForwarded[0]) {
3319 ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
3320 if (unforwardedOps == null) {
3321 unforwardedOps = new ArrayList<>(1);
3322 mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
3323 }
3324
3325 unforwardedOps.add(asyncNotedOp);
3326 if (unforwardedOps.size() > MAX_UNFORWARED_OPS) {
3327 unforwardedOps.remove(0);
3328 }
3329 }
3330 }
3331 } finally {
3332 Binder.restoreCallingIdentity(token);
3333 }
3334 }
3335
3336 /**
3337 * Compute a key to be used in {@link #mAsyncOpWatchers} and {@link #mUnforwardedAsyncNotedOps}
3338 *
3339 * @param packageName The package name of the app
3340 * @param uid The uid of the app
3341 *
3342 * @return They key uniquely identifying the app
3343 */
3344 private @NonNull Pair<String, Integer> getAsyncNotedOpsKey(@NonNull String packageName,
3345 int uid) {
3346 return new Pair<>(packageName, uid);
3347 }
3348
3349 @Override
3350 public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00003351 Objects.requireNonNull(packageName);
3352 Objects.requireNonNull(callback);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003353
3354 int uid = Binder.getCallingUid();
3355 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
3356
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003357 verifyAndGetBypass(uid, packageName, null);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003358
3359 synchronized (this) {
3360 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
3361 if (callbacks == null) {
3362 callbacks = new RemoteCallbackList<IAppOpsAsyncNotedCallback>() {
3363 @Override
3364 public void onCallbackDied(IAppOpsAsyncNotedCallback callback) {
3365 synchronized (AppOpsService.this) {
3366 if (getRegisteredCallbackCount() == 0) {
3367 mAsyncOpWatchers.remove(key);
3368 }
3369 }
3370 }
3371 };
3372 mAsyncOpWatchers.put(key, callbacks);
3373 }
3374
3375 callbacks.register(callback);
3376 }
3377 }
3378
3379 @Override
3380 public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00003381 Objects.requireNonNull(packageName);
3382 Objects.requireNonNull(callback);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003383
3384 int uid = Binder.getCallingUid();
3385 Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
3386
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003387 verifyAndGetBypass(uid, packageName, null);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003388
3389 synchronized (this) {
3390 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
3391 if (callbacks != null) {
3392 callbacks.unregister(callback);
3393 if (callbacks.getRegisteredCallbackCount() == 0) {
3394 mAsyncOpWatchers.remove(key);
3395 }
3396 }
3397 }
3398 }
3399
3400 @Override
3401 public List<AsyncNotedAppOp> extractAsyncOps(String packageName) {
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00003402 Objects.requireNonNull(packageName);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003403
3404 int uid = Binder.getCallingUid();
3405
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003406 verifyAndGetBypass(uid, packageName, null);
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003407
3408 synchronized (this) {
3409 return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
3410 }
3411 }
3412
3413 @Override
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003414 public int startOperation(IBinder clientId, int code, int uid, String packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003415 String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003416 String message) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003417 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08003418 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003419 String resolvedPackageName = resolvePackageName(uid, packageName);
3420 if (resolvedPackageName == null) {
3421 return AppOpsManager.MODE_IGNORED;
3422 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003423
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003424 RestrictionBypass bypass;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003425 try {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003426 bypass = verifyAndGetBypass(uid, packageName, attributionTag);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003427 } catch (SecurityException e) {
Philip P. Moltmannc5f504a2019-06-12 16:31:29 -07003428 Slog.e(TAG, "startOperation", e);
3429 return AppOpsManager.MODE_ERRORED;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003430 }
3431
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003432 synchronized (this) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003433 final Ops ops = getOpsLocked(uid, resolvedPackageName, attributionTag, bypass,
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003434 true /* edit */);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003435 if (ops == null) {
Adam Bookatz182862e2020-04-27 21:58:22 -07003436 scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003437 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003438 + " package " + resolvedPackageName);
Jeff Sharkey911d7f42013-09-05 18:11:45 -07003439 return AppOpsManager.MODE_ERRORED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003440 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003441 final Op op = getOpLocked(ops, code, uid, true);
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003442 if (isOpRestrictedLocked(uid, code, resolvedPackageName, bypass)) {
Adam Bookatz182862e2020-04-27 21:58:22 -07003443 scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED);
Jason Monk62062992014-05-06 09:55:28 -04003444 return AppOpsManager.MODE_IGNORED;
3445 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003446 final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003447 final int switchCode = AppOpsManager.opToSwitch(code);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07003448 final UidState uidState = ops.uidState;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003449 // If there is a non-default per UID policy (we set UID op mode only if
3450 // non-default) it takes over, otherwise use the per package policy.
Hai Zhang93540ca2019-09-28 00:04:18 +00003451 if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
3452 final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
Svet Ganovf7b47252018-02-26 11:11:27 -08003453 if (uidMode != AppOpsManager.MODE_ALLOWED
3454 && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003455 if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
Svet Ganov2af57082015-07-30 08:44:20 -07003456 + switchCode + " (" + code + ") uid " + uid + " package "
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003457 + resolvedPackageName);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003458 attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
Adam Bookatz182862e2020-04-27 21:58:22 -07003459 scheduleOpStartedIfNeededLocked(code, uid, packageName, uidMode);
Svet Ganov2af57082015-07-30 08:44:20 -07003460 return uidMode;
3461 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003462 } else {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003463 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
3464 : op;
Svet Ganovaf189e32019-02-15 18:45:29 -08003465 final int mode = switchOp.evalMode();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003466 if (mode != AppOpsManager.MODE_ALLOWED
3467 && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
3468 if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003469 + switchCode + " (" + code + ") uid " + uid + " package "
3470 + resolvedPackageName);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003471 attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
Adam Bookatz182862e2020-04-27 21:58:22 -07003472 scheduleOpStartedIfNeededLocked(code, uid, packageName, mode);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003473 return mode;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003474 }
Svet Ganov2af57082015-07-30 08:44:20 -07003475 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003476 if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003477 + " package " + resolvedPackageName);
Adam Bookatz182862e2020-04-27 21:58:22 -07003478 scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003479 try {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003480 attributedOp.started(clientId, uidState.state);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003481 } catch (RemoteException e) {
3482 throw new RuntimeException(e);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003483 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003484 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003485
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003486 if (shouldCollectAsyncNotedOp) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003487 collectAsyncNotedOp(uid, packageName, code, attributionTag, message);
Philip P. Moltmannda554e42019-12-20 11:21:02 -08003488 }
3489
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003490 return AppOpsManager.MODE_ALLOWED;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003491 }
3492
3493 @Override
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08003494 public void finishOperation(IBinder clientId, int code, int uid, String packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003495 String attributionTag) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003496 verifyIncomingUid(uid);
Dianne Hackborn961321f2013-02-05 17:22:41 -08003497 verifyIncomingOp(code);
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003498 String resolvedPackageName = resolvePackageName(uid, packageName);
3499 if (resolvedPackageName == null) {
3500 return;
3501 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003502
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003503 RestrictionBypass bypass;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003504 try {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003505 bypass = verifyAndGetBypass(uid, packageName, attributionTag);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003506 } catch (SecurityException e) {
3507 Slog.e(TAG, "Cannot finishOperation", e);
3508 return;
3509 }
3510
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003511 synchronized (this) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003512 Op op = getOpLocked(code, uid, resolvedPackageName, attributionTag, bypass, true);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003513 if (op == null) {
Philip P. Moltmann5ab15b02020-03-13 15:44:51 -07003514 Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
3515 + attributionTag + ") op=" + AppOpsManager.opToName(code));
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003516 return;
3517 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003518 final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
3519 if (attributedOp == null) {
Philip P. Moltmann5ab15b02020-03-13 15:44:51 -07003520 Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "("
3521 + attributionTag + ") op=" + AppOpsManager.opToName(code));
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003522 return;
3523 }
3524
Philip P. Moltmann5ab15b02020-03-13 15:44:51 -07003525 if (attributedOp.isRunning()) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003526 attributedOp.finished(clientId);
Philip P. Moltmann5ab15b02020-03-13 15:44:51 -07003527 } else {
3528 Slog.e(TAG, "Operation not started: uid=" + uid + " pkg=" + packageName + "("
3529 + attributionTag + ") op=" + AppOpsManager.opToName(code));
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003530 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003531 }
3532 }
3533
3534 private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
3535 boolean active) {
3536 ArraySet<ActiveCallback> dispatchedCallbacks = null;
3537 final int callbackListCount = mActiveWatchers.size();
3538 for (int i = 0; i < callbackListCount; i++) {
3539 final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
3540 ActiveCallback callback = callbacks.get(code);
3541 if (callback != null) {
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07003542 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
Svet Ganovf7b47252018-02-26 11:11:27 -08003543 continue;
3544 }
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003545 if (dispatchedCallbacks == null) {
3546 dispatchedCallbacks = new ArraySet<>();
3547 }
3548 dispatchedCallbacks.add(callback);
3549 }
3550 }
3551 if (dispatchedCallbacks == null) {
3552 return;
3553 }
3554 mHandler.sendMessage(PooledLambda.obtainMessage(
3555 AppOpsService::notifyOpActiveChanged,
3556 this, dispatchedCallbacks, code, uid, packageName, active));
3557 }
3558
3559 private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
3560 int code, int uid, String packageName, boolean active) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003561 // There are features watching for mode changes such as window manager
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003562 // and location manager which are in our process. The callbacks in these
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003563 // features may require permissions our remote caller does not have.
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08003564 final long identity = Binder.clearCallingIdentity();
3565 try {
3566 final int callbackCount = callbacks.size();
3567 for (int i = 0; i < callbackCount; i++) {
3568 final ActiveCallback callback = callbacks.valueAt(i);
3569 try {
3570 callback.mCallback.opActiveChanged(code, uid, packageName, active);
3571 } catch (RemoteException e) {
3572 /* do nothing */
3573 }
3574 }
3575 } finally {
3576 Binder.restoreCallingIdentity(identity);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07003577 }
3578 }
3579
Adam Bookatz182862e2020-04-27 21:58:22 -07003580 private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName, int result) {
3581 ArraySet<StartedCallback> dispatchedCallbacks = null;
3582 final int callbackListCount = mStartedWatchers.size();
3583 for (int i = 0; i < callbackListCount; i++) {
3584 final SparseArray<StartedCallback> callbacks = mStartedWatchers.valueAt(i);
3585
3586 StartedCallback callback = callbacks.get(code);
3587 if (callback != null) {
3588 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
3589 continue;
3590 }
3591
3592 if (dispatchedCallbacks == null) {
3593 dispatchedCallbacks = new ArraySet<>();
3594 }
3595 dispatchedCallbacks.add(callback);
3596 }
3597 }
3598
3599 if (dispatchedCallbacks == null) {
3600 return;
3601 }
3602
3603 mHandler.sendMessage(PooledLambda.obtainMessage(
3604 AppOpsService::notifyOpStarted,
3605 this, dispatchedCallbacks, code, uid, pkgName, result));
3606 }
3607
3608 private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
3609 int code, int uid, String packageName, int result) {
3610 final long identity = Binder.clearCallingIdentity();
3611 try {
3612 final int callbackCount = callbacks.size();
3613 for (int i = 0; i < callbackCount; i++) {
3614 final StartedCallback callback = callbacks.valueAt(i);
3615 try {
3616 callback.mCallback.opStarted(code, uid, packageName, result);
3617 } catch (RemoteException e) {
3618 /* do nothing */
3619 }
3620 }
3621 } finally {
3622 Binder.restoreCallingIdentity(identity);
3623 }
3624 }
3625
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003626 private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
3627 int result) {
3628 ArraySet<NotedCallback> dispatchedCallbacks = null;
3629 final int callbackListCount = mNotedWatchers.size();
3630 for (int i = 0; i < callbackListCount; i++) {
3631 final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
3632 final NotedCallback callback = callbacks.get(code);
3633 if (callback != null) {
3634 if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
3635 continue;
3636 }
3637 if (dispatchedCallbacks == null) {
3638 dispatchedCallbacks = new ArraySet<>();
3639 }
3640 dispatchedCallbacks.add(callback);
3641 }
3642 }
3643 if (dispatchedCallbacks == null) {
3644 return;
3645 }
3646 mHandler.sendMessage(PooledLambda.obtainMessage(
3647 AppOpsService::notifyOpChecked,
3648 this, dispatchedCallbacks, code, uid, packageName, result));
3649 }
3650
3651 private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
3652 int code, int uid, String packageName, int result) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07003653 // There are features watching for checks in our process. The callbacks in
3654 // these features may require permissions our remote caller does not have.
Svet Ganovb3d2ae22018-12-17 22:06:15 -08003655 final long identity = Binder.clearCallingIdentity();
3656 try {
3657 final int callbackCount = callbacks.size();
3658 for (int i = 0; i < callbackCount; i++) {
3659 final NotedCallback callback = callbacks.valueAt(i);
3660 try {
3661 callback.mCallback.opNoted(code, uid, packageName, result);
3662 } catch (RemoteException e) {
3663 /* do nothing */
3664 }
3665 }
3666 } finally {
3667 Binder.restoreCallingIdentity(identity);
3668 }
3669 }
3670
Svet Ganovb9d71a62015-04-30 10:38:13 -07003671 @Override
3672 public int permissionToOpCode(String permission) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00003673 if (permission == null) {
3674 return AppOpsManager.OP_NONE;
3675 }
Svet Ganovb9d71a62015-04-30 10:38:13 -07003676 return AppOpsManager.permissionToOpCode(permission);
3677 }
3678
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003679 @Override
3680 public boolean shouldCollectNotes(int opCode) {
3681 Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
3682
3683 String perm = AppOpsManager.opToPermission(opCode);
3684 if (perm == null) {
3685 return false;
3686 }
3687
3688 PermissionInfo permInfo;
3689 try {
3690 permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
3691 } catch (PackageManager.NameNotFoundException e) {
3692 return false;
3693 }
3694
Philip P. Moltmann87fd8bc2020-02-13 13:16:13 -08003695 return permInfo.getProtection() == PROTECTION_DANGEROUS
3696 || (permInfo.getProtectionFlags() & PROTECTION_FLAG_APPOP) != 0;
Philip P. Moltmann2b08aaf2019-06-10 08:49:11 -07003697 }
3698
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003699 private void verifyIncomingUid(int uid) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003700 if (uid == Binder.getCallingUid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003701 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003702 }
3703 if (Binder.getCallingPid() == Process.myPid()) {
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003704 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003705 }
3706 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
3707 Binder.getCallingPid(), Binder.getCallingUid(), null);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003708 }
3709
Dianne Hackborn961321f2013-02-05 17:22:41 -08003710 private void verifyIncomingOp(int op) {
3711 if (op >= 0 && op < AppOpsManager._NUM_OP) {
3712 return;
3713 }
3714 throw new IllegalArgumentException("Bad operation #" + op);
3715 }
3716
Philip P. Moltmann724150d2019-03-11 17:01:05 -07003717 private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07003718 UidState uidState = mUidStates.get(uid);
3719 if (uidState == null) {
3720 if (!edit) {
3721 return null;
3722 }
3723 uidState = new UidState(uid);
3724 mUidStates.put(uid, uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003725 } else {
Philip P. Moltmann463979e2020-01-24 14:41:22 -08003726 updatePendingStateIfNeededLocked(uidState);
3727 }
3728 return uidState;
3729 }
3730
3731 /**
3732 * Check if the pending state should be updated and do so if needed
3733 *
3734 * @param uidState The uidState that might have a pending state
3735 */
3736 private void updatePendingStateIfNeededLocked(@NonNull UidState uidState) {
3737 if (uidState != null) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003738 if (uidState.pendingStateCommitTime != 0) {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003739 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003740 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003741 } else {
Dianne Hackborn9fb93502018-06-18 12:29:44 -07003742 mLastRealtime = SystemClock.elapsedRealtime();
3743 if (uidState.pendingStateCommitTime < mLastRealtime) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003744 commitUidPendingStateLocked(uidState);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07003745 }
3746 }
3747 }
Svet Ganov2af57082015-07-30 08:44:20 -07003748 }
Svet Ganov2af57082015-07-30 08:44:20 -07003749 }
3750
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003751 private void commitUidPendingStateLocked(UidState uidState) {
Wei Wang878d0b62019-03-28 18:12:18 -07003752 if (uidState.hasForegroundWatchers) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003753 for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
3754 if (!uidState.foregroundOps.valueAt(fgi)) {
3755 continue;
3756 }
3757 final int code = uidState.foregroundOps.keyAt(fgi);
Svet Ganovaf189e32019-02-15 18:45:29 -08003758 // For location ops we consider fg state only if the fg service
3759 // is of location type, for all other ops any fg service will do.
Wei Wang711eb662019-03-21 18:24:17 -07003760 final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code);
3761 final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState;
3762 final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState;
Hui Yu88910de2019-12-16 14:35:27 -08003763 if (resolvedLastFg == resolvedNowFg
3764 && uidState.capability == uidState.pendingCapability
3765 && uidState.appWidgetVisible == uidState.pendingAppWidgetVisible) {
Svet Ganovaf189e32019-02-15 18:45:29 -08003766 continue;
3767 }
Philip P. Moltmann584c23a2020-01-24 14:21:12 -08003768
3769 if (uidState.opModes != null
3770 && uidState.opModes.indexOfKey(code) >= 0
3771 && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND) {
3772 mHandler.sendMessage(PooledLambda.obtainMessage(
3773 AppOpsService::notifyOpChangedForAllPkgsInUid,
3774 this, code, uidState.uid, true, null));
3775 } else {
3776 final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
3777 if (callbacks != null) {
3778 for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
3779 final ModeCallback callback = callbacks.valueAt(cbi);
3780 if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
3781 || !callback.isWatchingUid(uidState.uid)) {
3782 continue;
3783 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003784 for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
3785 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
Svet Ganovaf189e32019-02-15 18:45:29 -08003786 if (op == null) {
3787 continue;
3788 }
Philip P. Moltmann584c23a2020-01-24 14:21:12 -08003789 if (op.mode == AppOpsManager.MODE_FOREGROUND) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003790 mHandler.sendMessage(PooledLambda.obtainMessage(
3791 AppOpsService::notifyOpChanged,
3792 this, callback, code, uidState.uid,
3793 uidState.pkgOps.keyAt(pkgi)));
3794 }
3795 }
3796 }
3797 }
3798 }
3799 }
3800 }
Wei Wang711eb662019-03-21 18:24:17 -07003801 uidState.state = uidState.pendingState;
Hui Yu26969322019-08-21 14:56:35 -07003802 uidState.capability = uidState.pendingCapability;
Hui Yu88910de2019-12-16 14:35:27 -08003803 uidState.appWidgetVisible = uidState.pendingAppWidgetVisible;
Wei Wang711eb662019-03-21 18:24:17 -07003804 uidState.pendingStateCommitTime = 0;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07003805 }
3806
Hui Yu88910de2019-12-16 14:35:27 -08003807 private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
3808 synchronized (this) {
3809 for (int i = uidPackageNames.size() - 1; i >= 0; i--) {
3810 final int uid = uidPackageNames.keyAt(i);
3811 final UidState uidState = getUidStateLocked(uid, true);
3812 if (uidState != null && (uidState.pendingAppWidgetVisible != visible)) {
3813 uidState.pendingAppWidgetVisible = visible;
3814 if (uidState.pendingAppWidgetVisible != uidState.appWidgetVisible) {
3815 commitUidPendingStateLocked(uidState);
3816 }
3817 }
3818 }
3819 }
3820 }
3821
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003822 /**
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003823 * Create a restriction description matching the properties of the package.
3824 *
3825 * @param context A context to use
3826 * @param pkg The package to create the restriction description for
3827 *
3828 * @return The restriction matching the package
3829 */
3830 private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) {
3831 return new RestrictionBypass(pkg.isPrivileged(), mContext.checkPermission(
3832 android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
3833 == PackageManager.PERMISSION_GRANTED);
3834 }
3835
3836 /**
3837 * Verify that package belongs to uid and return the {@link RestrictionBypass bypass
3838 * description} for the package.
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003839 *
3840 * @param uid The uid the package belongs to
3841 * @param packageName The package the might belong to the uid
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003842 * @param attributionTag attribution tag or {@code null} if no need to verify
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003843 *
3844 * @return {@code true} iff the package is privileged
3845 */
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003846 private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003847 @Nullable String attributionTag) {
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003848 if (uid == Process.ROOT_UID) {
3849 // For backwards compatibility, don't check package name for root UID.
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003850 return null;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003851 }
3852
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003853 // Do not check if uid/packageName/attributionTag is already known
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003854 synchronized (this) {
3855 UidState uidState = mUidStates.get(uid);
3856 if (uidState != null && uidState.pkgOps != null) {
3857 Ops ops = uidState.pkgOps.get(packageName);
3858
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003859 if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains(
3860 attributionTag)) && ops.bypass != null) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003861 return ops.bypass;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003862 }
3863 }
3864 }
3865
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003866 RestrictionBypass bypass = null;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003867 final long ident = Binder.clearCallingIdentity();
3868 try {
3869 int pkgUid;
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003870 AndroidPackage pkg = LocalServices.getService(PackageManagerInternal.class).getPackage(
3871 packageName);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003872 boolean isAttributionTagValid = false;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003873
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003874 if (pkg != null) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003875 if (attributionTag == null) {
3876 isAttributionTagValid = true;
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003877 } else {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003878 if (pkg.getAttributions() != null) {
3879 int numAttributions = pkg.getAttributions().size();
3880 for (int i = 0; i < numAttributions; i++) {
3881 if (pkg.getAttributions().get(i).tag.equals(attributionTag)) {
3882 isAttributionTagValid = true;
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003883 }
3884 }
3885 }
3886 }
3887
3888 pkgUid = UserHandle.getUid(
3889 UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid()));
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003890 bypass = getBypassforPackage(pkg);
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003891 } else {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003892 // Allow any attribution tag for resolvable uids
3893 isAttributionTagValid = true;
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003894
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003895 pkgUid = resolveUid(packageName);
3896 if (pkgUid >= 0) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003897 bypass = RestrictionBypass.UNRESTRICTED;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003898 }
3899 }
3900 if (pkgUid != uid) {
3901 throw new SecurityException("Specified package " + packageName + " under uid " + uid
3902 + " but it is really " + pkgUid);
3903 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003904
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003905 if (!isAttributionTagValid) {
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003906 // TODO moltmann: Switch from logging to enforcement
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003907 Slog.e(TAG, "attributionTag " + attributionTag + " not declared in manifest of "
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003908 + packageName);
3909 }
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003910 } finally {
3911 Binder.restoreCallingIdentity(ident);
3912 }
3913
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003914 return bypass;
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003915 }
3916
3917 /**
3918 * Get (and potentially create) ops.
3919 *
3920 * @param uid The uid the package belongs to
3921 * @param packageName The name of the package
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003922 * @param attributionTag attribution tag
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003923 * @param bypass When to bypass certain op restrictions (can be null if edit == false)
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003924 * @param edit If an ops does not exist, create the ops?
3925
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003926 * @return The ops
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003927 */
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003928 private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag,
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003929 @Nullable RestrictionBypass bypass, boolean edit) {
Svet Ganov2af57082015-07-30 08:44:20 -07003930 UidState uidState = getUidStateLocked(uid, edit);
3931 if (uidState == null) {
3932 return null;
3933 }
3934
3935 if (uidState.pkgOps == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003936 if (!edit) {
3937 return null;
3938 }
Svet Ganov2af57082015-07-30 08:44:20 -07003939 uidState.pkgOps = new ArrayMap<>();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003940 }
Svet Ganov2af57082015-07-30 08:44:20 -07003941
3942 Ops ops = uidState.pkgOps.get(packageName);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08003943 if (ops == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08003944 if (!edit) {
3945 return null;
3946 }
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003947 ops = new Ops(packageName, uidState);
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003948 uidState.pkgOps.put(packageName, ops);
3949 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003950
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003951 if (edit) {
3952 if (bypass != null) {
3953 ops.bypass = bypass;
3954 }
3955
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003956 if (attributionTag != null) {
3957 ops.knownAttributionTags.add(attributionTag);
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003958 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003959 }
3960
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003961 return ops;
3962 }
3963
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003964 private void scheduleWriteLocked() {
3965 if (!mWriteScheduled) {
3966 mWriteScheduled = true;
3967 mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
3968 }
3969 }
3970
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003971 private void scheduleFastWriteLocked() {
3972 if (!mFastWriteScheduled) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003973 mWriteScheduled = true;
Dianne Hackborn7b7c58b2014-12-02 18:32:20 -08003974 mFastWriteScheduled = true;
3975 mHandler.removeCallbacks(mWriteRunner);
3976 mHandler.postDelayed(mWriteRunner, 10*1000);
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003977 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003978 }
3979
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003980 /**
3981 * Get the state of an op for a uid.
3982 *
3983 * @param code The code of the op
3984 * @param uid The uid the of the package
3985 * @param packageName The package name for which to get the state for
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003986 * @param attributionTag The attribution tag
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07003987 * @param bypass When to bypass certain op restrictions (can be null if edit == false)
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003988 * @param edit Iff {@code true} create the {@link Op} object if not yet created
Philip P. Moltmann17f65af2018-10-18 15:32:29 -07003989 *
3990 * @return The {@link Op state} of the op
3991 */
Philip P. Moltmannec142a52019-04-09 13:38:07 -07003992 private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08003993 @Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit) {
3994 Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, edit);
Dianne Hackborn72e39832013-01-18 18:36:09 -08003995 if (ops == null) {
3996 return null;
3997 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08003998 return getOpLocked(ops, code, uid, edit);
Dianne Hackbornf265ea92013-01-31 15:00:51 -08003999 }
4000
Philip P. Moltmann9046d822019-12-13 15:59:49 -08004001 private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004002 Op op = ops.get(code);
4003 if (op == null) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08004004 if (!edit) {
4005 return null;
4006 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08004007 op = new Op(ops.uidState, ops.packageName, code, uid);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004008 ops.put(code, op);
4009 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08004010 if (edit) {
4011 scheduleWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08004012 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08004013 return op;
4014 }
4015
Suprabh Shukla7e017922019-08-05 17:13:23 -07004016 private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
Suprabh Shuklab614a222019-09-12 14:42:46 -07004017 if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) {
4018 return false;
4019 }
Suprabh Shukla7e017922019-08-05 17:13:23 -07004020 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Suprabh Shuklab614a222019-09-12 14:42:46 -07004021 return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
Suprabh Shukla7e017922019-08-05 17:13:23 -07004022 }
4023
Philip P. Moltmannec142a52019-04-09 13:38:07 -07004024 private boolean isOpRestrictedLocked(int uid, int code, String packageName,
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07004025 @Nullable RestrictionBypass appBypass) {
Jason Monk62062992014-05-06 09:55:28 -04004026 int userHandle = UserHandle.getUserId(uid);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004027 final int restrictionSetCount = mOpUserRestrictions.size();
Ruben Brunk29931bc2016-03-11 00:24:26 -08004028
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004029 for (int i = 0; i < restrictionSetCount; i++) {
Ruben Brunk29931bc2016-03-11 00:24:26 -08004030 // For each client, check that the given op is not restricted, or that the given
4031 // package is exempt from the restriction.
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07004032 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07004033 if (restrictionState.hasRestriction(code, packageName, userHandle)) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07004034 RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
4035 if (opBypass != null) {
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07004036 // If we are the system, bypass user restrictions for certain codes
4037 synchronized (this) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07004038 if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
4039 return false;
4040 }
4041 if (opBypass.isRecordAudioRestrictionExcept && appBypass != null
4042 && appBypass.isRecordAudioRestrictionExcept) {
Suprabh Shuklaffddadb2016-05-20 16:37:26 -07004043 return false;
4044 }
Ruben Brunk32f0fa42016-03-11 19:07:07 -08004045 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08004046 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08004047 return true;
Jason Monk1c7c3192014-06-26 12:52:18 -04004048 }
Jason Monk62062992014-05-06 09:55:28 -04004049 }
4050 return false;
4051 }
4052
Dianne Hackborn35654b62013-01-14 17:38:02 -08004053 void readState() {
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004054 int oldVersion = NO_VERSION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08004055 synchronized (mFile) {
4056 synchronized (this) {
4057 FileInputStream stream;
4058 try {
4059 stream = mFile.openRead();
4060 } catch (FileNotFoundException e) {
4061 Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
4062 return;
4063 }
4064 boolean success = false;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004065 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08004066 try {
4067 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01004068 parser.setInput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08004069 int type;
4070 while ((type = parser.next()) != XmlPullParser.START_TAG
4071 && type != XmlPullParser.END_DOCUMENT) {
4072 ;
4073 }
4074
4075 if (type != XmlPullParser.START_TAG) {
4076 throw new IllegalStateException("no start tag found");
4077 }
4078
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004079 final String versionString = parser.getAttributeValue(null, "v");
4080 if (versionString != null) {
4081 oldVersion = Integer.parseInt(versionString);
4082 }
4083
Dianne Hackborn35654b62013-01-14 17:38:02 -08004084 int outerDepth = parser.getDepth();
4085 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4086 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4087 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4088 continue;
4089 }
4090
4091 String tagName = parser.getName();
4092 if (tagName.equals("pkg")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00004093 readPackage(parser);
Svetoslav215b44a2015-08-04 19:03:40 -07004094 } else if (tagName.equals("uid")) {
Svet Ganov2af57082015-07-30 08:44:20 -07004095 readUidOps(parser);
Dianne Hackborn35654b62013-01-14 17:38:02 -08004096 } else {
4097 Slog.w(TAG, "Unknown element under <app-ops>: "
4098 + parser.getName());
4099 XmlUtils.skipCurrentTag(parser);
4100 }
4101 }
4102 success = true;
4103 } catch (IllegalStateException e) {
4104 Slog.w(TAG, "Failed parsing " + e);
4105 } catch (NullPointerException e) {
4106 Slog.w(TAG, "Failed parsing " + e);
4107 } catch (NumberFormatException e) {
4108 Slog.w(TAG, "Failed parsing " + e);
4109 } catch (XmlPullParserException e) {
4110 Slog.w(TAG, "Failed parsing " + e);
4111 } catch (IOException e) {
4112 Slog.w(TAG, "Failed parsing " + e);
4113 } catch (IndexOutOfBoundsException e) {
4114 Slog.w(TAG, "Failed parsing " + e);
4115 } finally {
4116 if (!success) {
Svet Ganov2af57082015-07-30 08:44:20 -07004117 mUidStates.clear();
Dianne Hackborn35654b62013-01-14 17:38:02 -08004118 }
4119 try {
4120 stream.close();
4121 } catch (IOException e) {
4122 }
4123 }
4124 }
4125 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004126 synchronized (this) {
4127 upgradeLocked(oldVersion);
4128 }
4129 }
4130
4131 private void upgradeRunAnyInBackgroundLocked() {
4132 for (int i = 0; i < mUidStates.size(); i++) {
4133 final UidState uidState = mUidStates.valueAt(i);
4134 if (uidState == null) {
4135 continue;
4136 }
Hai Zhang93540ca2019-09-28 00:04:18 +00004137 if (uidState.opModes != null) {
4138 final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
4139 if (idx >= 0) {
4140 uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
4141 uidState.opModes.valueAt(idx));
4142 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004143 }
4144 if (uidState.pkgOps == null) {
4145 continue;
4146 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004147 boolean changed = false;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004148 for (int j = 0; j < uidState.pkgOps.size(); j++) {
4149 Ops ops = uidState.pkgOps.valueAt(j);
4150 if (ops != null) {
4151 final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
4152 if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004153 final Op copy = new Op(op.uidState, op.packageName,
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004154 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uidState.uid);
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004155 copy.mode = op.mode;
4156 ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004157 changed = true;
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004158 }
4159 }
4160 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004161 if (changed) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004162 uidState.evalForegroundOps(mOpModeWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004163 }
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004164 }
4165 }
4166
4167 private void upgradeLocked(int oldVersion) {
4168 if (oldVersion >= CURRENT_VERSION) {
4169 return;
4170 }
4171 Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
4172 switch (oldVersion) {
4173 case NO_VERSION:
4174 upgradeRunAnyInBackgroundLocked();
4175 // fall through
4176 case 1:
4177 // for future upgrades
4178 }
4179 scheduleFastWriteLocked();
Dianne Hackborn35654b62013-01-14 17:38:02 -08004180 }
4181
Svet Ganovaf189e32019-02-15 18:45:29 -08004182 private void readUidOps(XmlPullParser parser) throws NumberFormatException,
Svet Ganov2af57082015-07-30 08:44:20 -07004183 XmlPullParserException, IOException {
4184 final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
4185 int outerDepth = parser.getDepth();
4186 int type;
4187 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4188 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4189 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4190 continue;
4191 }
4192
4193 String tagName = parser.getName();
4194 if (tagName.equals("op")) {
4195 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
4196 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
Philip P. Moltmann94faa4a2020-01-30 14:16:40 -08004197 setUidMode(code, uid, mode);
Svet Ganov2af57082015-07-30 08:44:20 -07004198 } else {
4199 Slog.w(TAG, "Unknown element under <uid-ops>: "
4200 + parser.getName());
4201 XmlUtils.skipCurrentTag(parser);
4202 }
4203 }
4204 }
4205
Svet Ganovaf189e32019-02-15 18:45:29 -08004206 private void readPackage(XmlPullParser parser)
4207 throws NumberFormatException, XmlPullParserException, IOException {
Dianne Hackborn35654b62013-01-14 17:38:02 -08004208 String pkgName = parser.getAttributeValue(null, "n");
4209 int outerDepth = parser.getDepth();
4210 int type;
4211 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4212 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4213 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4214 continue;
4215 }
4216
4217 String tagName = parser.getName();
4218 if (tagName.equals("uid")) {
Dave Burke0997c5bd2013-08-02 20:25:02 +00004219 readUid(parser, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08004220 } else {
4221 Slog.w(TAG, "Unknown element under <pkg>: "
4222 + parser.getName());
4223 XmlUtils.skipCurrentTag(parser);
4224 }
4225 }
4226 }
4227
Svet Ganovaf189e32019-02-15 18:45:29 -08004228 private void readUid(XmlPullParser parser, String pkgName)
4229 throws NumberFormatException, XmlPullParserException, IOException {
Dianne Hackborn35654b62013-01-14 17:38:02 -08004230 int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
Svet Ganovaf189e32019-02-15 18:45:29 -08004231 final UidState uidState = getUidStateLocked(uid, true);
Dianne Hackborn35654b62013-01-14 17:38:02 -08004232 int outerDepth = parser.getDepth();
4233 int type;
4234 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4235 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4236 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4237 continue;
4238 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08004239 String tagName = parser.getName();
4240 if (tagName.equals("op")) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07004241 readOp(parser, uidState, pkgName);
Dianne Hackborn35654b62013-01-14 17:38:02 -08004242 } else {
4243 Slog.w(TAG, "Unknown element under <pkg>: "
4244 + parser.getName());
4245 XmlUtils.skipCurrentTag(parser);
4246 }
4247 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004248 uidState.evalForegroundOps(mOpModeWatchers);
4249 }
4250
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004251 private void readAttributionOp(XmlPullParser parser, @NonNull Op parent,
4252 @Nullable String attribution) throws NumberFormatException, IOException {
4253 final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004254
4255 final long key = XmlUtils.readLongAttribute(parser, "n");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004256 final int uidState = extractUidStateFromKey(key);
4257 final int opFlags = extractFlagsFromKey(key);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004258
4259 final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0);
4260 final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004261 final long accessDuration = XmlUtils.readLongAttribute(parser, "d", -1);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004262 final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004263 final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", Process.INVALID_UID);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004264 final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004265
4266 if (accessTime > 0) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004267 attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg,
4268 proxyAttributionTag, uidState, opFlags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004269 }
4270 if (rejectTime > 0) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004271 attributedOp.rejected(rejectTime, uidState, opFlags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004272 }
4273 }
4274
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07004275 private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)
4276 throws NumberFormatException,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004277 XmlPullParserException, IOException {
shafik3ea80352020-02-21 15:29:58 +00004278 int opCode = Integer.parseInt(parser.getAttributeValue(null, "n"));
shafik3ea80352020-02-21 15:29:58 +00004279 Op op = new Op(uidState, pkgName, opCode, uidState.uid);
Svet Ganovaf189e32019-02-15 18:45:29 -08004280
4281 final int mode = XmlUtils.readIntAttribute(parser, "m",
4282 AppOpsManager.opToDefaultMode(op.op));
4283 op.mode = mode;
4284
4285 int outerDepth = parser.getDepth();
4286 int type;
4287 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4288 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4289 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4290 continue;
4291 }
4292 String tagName = parser.getName();
4293 if (tagName.equals("st")) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004294 readAttributionOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
Svet Ganovaf189e32019-02-15 18:45:29 -08004295 } else {
4296 Slog.w(TAG, "Unknown element under <op>: "
4297 + parser.getName());
4298 XmlUtils.skipCurrentTag(parser);
4299 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004300 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004301
4302 if (uidState.pkgOps == null) {
4303 uidState.pkgOps = new ArrayMap<>();
4304 }
4305 Ops ops = uidState.pkgOps.get(pkgName);
4306 if (ops == null) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07004307 ops = new Ops(pkgName, uidState);
Svet Ganovaf189e32019-02-15 18:45:29 -08004308 uidState.pkgOps.put(pkgName, ops);
4309 }
4310 ops.put(op.op, op);
Dianne Hackborn35654b62013-01-14 17:38:02 -08004311 }
4312
4313 void writeState() {
4314 synchronized (mFile) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08004315 FileOutputStream stream;
4316 try {
4317 stream = mFile.startWrite();
4318 } catch (IOException e) {
4319 Slog.w(TAG, "Failed to write state: " + e);
4320 return;
4321 }
4322
Dianne Hackborne17b4452018-01-10 13:15:40 -08004323 List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
4324
Dianne Hackborn35654b62013-01-14 17:38:02 -08004325 try {
4326 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01004327 out.setOutput(stream, StandardCharsets.UTF_8.name());
Dianne Hackborn35654b62013-01-14 17:38:02 -08004328 out.startDocument(null, true);
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004329 out.startTag(null, "app-ops");
Suprabh Shukla3ac1daa2017-07-14 12:15:27 -07004330 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
Svet Ganov2af57082015-07-30 08:44:20 -07004331
Hai Zhang93540ca2019-09-28 00:04:18 +00004332 SparseArray<SparseIntArray> uidStatesClone;
Eugene Susla463d5922019-07-17 18:14:15 -07004333 synchronized (this) {
Hai Zhang93540ca2019-09-28 00:04:18 +00004334 uidStatesClone = new SparseArray<>(mUidStates.size());
4335
4336 final int uidStateCount = mUidStates.size();
4337 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
4338 UidState uidState = mUidStates.valueAt(uidStateNum);
4339 int uid = mUidStates.keyAt(uidStateNum);
4340
4341 SparseIntArray opModes = uidState.opModes;
4342 if (opModes != null && opModes.size() > 0) {
4343 uidStatesClone.put(uid, new SparseIntArray(opModes.size()));
4344
4345 final int opCount = opModes.size();
4346 for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
4347 uidStatesClone.get(uid).put(
4348 opModes.keyAt(opCountNum),
4349 opModes.valueAt(opCountNum));
4350 }
Svet Ganov2af57082015-07-30 08:44:20 -07004351 }
Svet Ganov2af57082015-07-30 08:44:20 -07004352 }
4353 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08004354
Hai Zhang93540ca2019-09-28 00:04:18 +00004355 final int uidStateCount = uidStatesClone.size();
4356 for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
4357 SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
4358 if (opModes != null && opModes.size() > 0) {
4359 out.startTag(null, "uid");
4360 out.attribute(null, "n",
4361 Integer.toString(uidStatesClone.keyAt(uidStateNum)));
4362 final int opCount = opModes.size();
4363 for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
4364 final int op = opModes.keyAt(opCountNum);
4365 final int mode = opModes.valueAt(opCountNum);
4366 out.startTag(null, "op");
4367 out.attribute(null, "n", Integer.toString(op));
4368 out.attribute(null, "m", Integer.toString(mode));
4369 out.endTag(null, "op");
4370 }
4371 out.endTag(null, "uid");
Eugene Susla11b706c2019-08-28 14:28:32 -07004372 }
4373 }
4374
Dianne Hackborn35654b62013-01-14 17:38:02 -08004375 if (allOps != null) {
4376 String lastPkg = null;
4377 for (int i=0; i<allOps.size(); i++) {
4378 AppOpsManager.PackageOps pkg = allOps.get(i);
4379 if (!pkg.getPackageName().equals(lastPkg)) {
4380 if (lastPkg != null) {
4381 out.endTag(null, "pkg");
4382 }
4383 lastPkg = pkg.getPackageName();
4384 out.startTag(null, "pkg");
4385 out.attribute(null, "n", lastPkg);
4386 }
4387 out.startTag(null, "uid");
4388 out.attribute(null, "n", Integer.toString(pkg.getUid()));
4389 List<AppOpsManager.OpEntry> ops = pkg.getOps();
4390 for (int j=0; j<ops.size(); j++) {
4391 AppOpsManager.OpEntry op = ops.get(j);
4392 out.startTag(null, "op");
4393 out.attribute(null, "n", Integer.toString(op.getOp()));
David Braunf5d83192013-09-16 13:43:51 -07004394 if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08004395 out.attribute(null, "m", Integer.toString(op.getMode()));
4396 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004397
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004398 for (String attributionTag : op.getAttributedOpEntries().keySet()) {
4399 final AttributedOpEntry attribution =
4400 op.getAttributedOpEntries().get(attributionTag);
Svet Ganovaf189e32019-02-15 18:45:29 -08004401
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004402 final ArraySet<Long> keys = attribution.collectKeys();
Svet Ganovaf189e32019-02-15 18:45:29 -08004403
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004404 final int keyCount = keys.size();
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004405 for (int k = 0; k < keyCount; k++) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004406 final long key = keys.valueAt(k);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004407
4408 final int uidState = AppOpsManager.extractUidStateFromKey(key);
4409 final int flags = AppOpsManager.extractFlagsFromKey(key);
4410
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004411 final long accessTime = attribution.getLastAccessTime(uidState,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004412 uidState, flags);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004413 final long rejectTime = attribution.getLastRejectTime(uidState,
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004414 uidState, flags);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004415 final long accessDuration = attribution.getLastDuration(
4416 uidState, uidState, flags);
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004417 // Proxy information for rejections is not backed up
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004418 final OpEventProxyInfo proxy = attribution.getLastProxyInfo(
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004419 uidState, uidState, flags);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004420
4421 if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004422 && proxy == null) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004423 continue;
4424 }
4425
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004426 String proxyPkg = null;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004427 String proxyAttributionTag = null;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004428 int proxyUid = Process.INVALID_UID;
4429 if (proxy != null) {
4430 proxyPkg = proxy.getPackageName();
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004431 proxyAttributionTag = proxy.getAttributionTag();
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004432 proxyUid = proxy.getUid();
4433 }
4434
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004435 out.startTag(null, "st");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004436 if (attributionTag != null) {
4437 out.attribute(null, "id", attributionTag);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004438 }
4439 out.attribute(null, "n", Long.toString(key));
4440 if (accessTime > 0) {
4441 out.attribute(null, "t", Long.toString(accessTime));
4442 }
4443 if (rejectTime > 0) {
4444 out.attribute(null, "r", Long.toString(rejectTime));
4445 }
4446 if (accessDuration > 0) {
4447 out.attribute(null, "d", Long.toString(accessDuration));
4448 }
4449 if (proxyPkg != null) {
4450 out.attribute(null, "pp", proxyPkg);
4451 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004452 if (proxyAttributionTag != null) {
4453 out.attribute(null, "pc", proxyAttributionTag);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004454 }
4455 if (proxyUid >= 0) {
4456 out.attribute(null, "pu", Integer.toString(proxyUid));
4457 }
4458 out.endTag(null, "st");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004459 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08004460 }
Svet Ganovaf189e32019-02-15 18:45:29 -08004461
Dianne Hackborn35654b62013-01-14 17:38:02 -08004462 out.endTag(null, "op");
4463 }
4464 out.endTag(null, "uid");
4465 }
4466 if (lastPkg != null) {
4467 out.endTag(null, "pkg");
4468 }
4469 }
4470
4471 out.endTag(null, "app-ops");
4472 out.endDocument();
4473 mFile.finishWrite(stream);
4474 } catch (IOException e) {
4475 Slog.w(TAG, "Failed to write state, restoring backup.", e);
4476 mFile.failWrite(stream);
4477 }
4478 }
4479 }
4480
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004481 static class Shell extends ShellCommand {
4482 final IAppOpsService mInterface;
4483 final AppOpsService mInternal;
4484
4485 int userId = UserHandle.USER_SYSTEM;
4486 String packageName;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004487 String attributionTag;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004488 String opStr;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004489 String modeStr;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004490 int op;
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004491 int mode;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004492 int packageUid;
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004493 int nonpackageUid;
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004494 final static Binder sBinder = new Binder();
4495 IBinder mToken;
Svet Ganovd563e932019-04-14 13:07:41 -07004496 boolean targetsUid;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004497
4498 Shell(IAppOpsService iface, AppOpsService internal) {
4499 mInterface = iface;
4500 mInternal = internal;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08004501 mToken = AppOpsManager.getClientId();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004502 }
4503
4504 @Override
4505 public int onCommand(String cmd) {
4506 return onShellCommand(this, cmd);
4507 }
4508
4509 @Override
4510 public void onHelp() {
4511 PrintWriter pw = getOutPrintWriter();
4512 dumpCommandHelp(pw);
4513 }
4514
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004515 static private int strOpToOp(String op, PrintWriter err) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004516 try {
4517 return AppOpsManager.strOpToOp(op);
4518 } catch (IllegalArgumentException e) {
4519 }
4520 try {
4521 return Integer.parseInt(op);
4522 } catch (NumberFormatException e) {
4523 }
4524 try {
4525 return AppOpsManager.strDebugOpToOp(op);
4526 } catch (IllegalArgumentException e) {
4527 err.println("Error: " + e.getMessage());
4528 return -1;
4529 }
4530 }
4531
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004532 static int strModeToMode(String modeStr, PrintWriter err) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004533 for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
4534 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07004535 return i;
4536 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004537 }
4538 try {
4539 return Integer.parseInt(modeStr);
4540 } catch (NumberFormatException e) {
4541 }
4542 err.println("Error: Mode " + modeStr + " is not valid");
4543 return -1;
4544 }
4545
4546 int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
4547 userId = UserHandle.USER_CURRENT;
4548 opStr = null;
4549 modeStr = null;
4550 for (String argument; (argument = getNextArg()) != null;) {
4551 if ("--user".equals(argument)) {
4552 userId = UserHandle.parseUserArg(getNextArgRequired());
4553 } else {
4554 if (opStr == null) {
4555 opStr = argument;
4556 } else if (modeStr == null) {
4557 modeStr = argument;
4558 break;
4559 }
4560 }
4561 }
4562 if (opStr == null) {
4563 err.println("Error: Operation not specified.");
4564 return -1;
4565 }
4566 op = strOpToOp(opStr, err);
4567 if (op < 0) {
4568 return -1;
4569 }
4570 if (modeStr != null) {
4571 if ((mode=strModeToMode(modeStr, err)) < 0) {
4572 return -1;
4573 }
4574 } else {
4575 mode = defMode;
4576 }
4577 return 0;
4578 }
4579
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004580 int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
4581 userId = UserHandle.USER_CURRENT;
4582 packageName = null;
4583 opStr = null;
4584 for (String argument; (argument = getNextArg()) != null;) {
4585 if ("--user".equals(argument)) {
4586 userId = UserHandle.parseUserArg(getNextArgRequired());
Svet Ganovd563e932019-04-14 13:07:41 -07004587 } else if ("--uid".equals(argument)) {
4588 targetsUid = true;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004589 } else if ("--attribution".equals(argument)) {
4590 attributionTag = getNextArgRequired();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004591 } else {
4592 if (packageName == null) {
4593 packageName = argument;
4594 } else if (opStr == null) {
4595 opStr = argument;
4596 break;
4597 }
4598 }
4599 }
4600 if (packageName == null) {
4601 err.println("Error: Package name not specified.");
4602 return -1;
4603 } else if (opStr == null && reqOp) {
4604 err.println("Error: Operation not specified.");
4605 return -1;
4606 }
4607 if (opStr != null) {
4608 op = strOpToOp(opStr, err);
4609 if (op < 0) {
4610 return -1;
4611 }
4612 } else {
4613 op = AppOpsManager.OP_NONE;
4614 }
4615 if (userId == UserHandle.USER_CURRENT) {
4616 userId = ActivityManager.getCurrentUser();
4617 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004618 nonpackageUid = -1;
4619 try {
4620 nonpackageUid = Integer.parseInt(packageName);
4621 } catch (NumberFormatException e) {
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004622 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004623 if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
4624 && packageName.indexOf('.') < 0) {
4625 int i = 1;
4626 while (i < packageName.length() && packageName.charAt(i) >= '0'
4627 && packageName.charAt(i) <= '9') {
4628 i++;
4629 }
4630 if (i > 1 && i < packageName.length()) {
4631 String userStr = packageName.substring(1, i);
4632 try {
4633 int user = Integer.parseInt(userStr);
4634 char type = packageName.charAt(i);
4635 i++;
4636 int startTypeVal = i;
4637 while (i < packageName.length() && packageName.charAt(i) >= '0'
4638 && packageName.charAt(i) <= '9') {
4639 i++;
4640 }
4641 if (i > startTypeVal) {
4642 String typeValStr = packageName.substring(startTypeVal, i);
4643 try {
4644 int typeVal = Integer.parseInt(typeValStr);
4645 if (type == 'a') {
4646 nonpackageUid = UserHandle.getUid(user,
4647 typeVal + Process.FIRST_APPLICATION_UID);
4648 } else if (type == 's') {
4649 nonpackageUid = UserHandle.getUid(user, typeVal);
4650 }
4651 } catch (NumberFormatException e) {
4652 }
4653 }
4654 } catch (NumberFormatException e) {
4655 }
4656 }
4657 }
4658 if (nonpackageUid != -1) {
4659 packageName = null;
4660 } else {
Svet Ganov82f09bc2018-01-12 22:08:40 -08004661 packageUid = resolveUid(packageName);
4662 if (packageUid < 0) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004663 packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
4664 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
4665 }
4666 if (packageUid < 0) {
4667 err.println("Error: No UID for " + packageName + " in user " + userId);
4668 return -1;
4669 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004670 }
4671 return 0;
4672 }
4673 }
4674
4675 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07004676 FileDescriptor err, String[] args, ShellCallback callback,
4677 ResultReceiver resultReceiver) {
4678 (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004679 }
4680
4681 static void dumpCommandHelp(PrintWriter pw) {
4682 pw.println("AppOps service (appops) commands:");
4683 pw.println(" help");
4684 pw.println(" Print this help text.");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004685 pw.println(" start [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
4686 + "<OP> ");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004687 pw.println(" Starts a given operation for a particular application.");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004688 pw.println(" stop [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
4689 + "<OP> ");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004690 pw.println(" Stops a given operation for a particular application.");
Svet Ganovb687fad2019-04-30 17:32:44 -07004691 pw.println(" set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004692 pw.println(" Set the mode for a particular application and operation.");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004693 pw.println(" get [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
4694 + "[<OP>]");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004695 pw.println(" Return the mode for a particular application and optional operation.");
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004696 pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
4697 pw.println(" Print all packages that currently have the given op in the given mode.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004698 pw.println(" reset [--user <USER_ID>] [<PACKAGE>]");
4699 pw.println(" Reset the given application or all applications to default modes.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004700 pw.println(" write-settings");
4701 pw.println(" Immediately write pending changes to storage.");
4702 pw.println(" read-settings");
4703 pw.println(" Read the last written settings, replacing current state in RAM.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004704 pw.println(" options:");
Svet Ganovb687fad2019-04-30 17:32:44 -07004705 pw.println(" <PACKAGE> an Android package name or its UID if prefixed by --uid");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004706 pw.println(" <OP> an AppOps operation.");
4707 pw.println(" <MODE> one of allow, ignore, deny, or default");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004708 pw.println(" <USER_ID> the user id under which the package is installed. If --user is");
4709 pw.println(" not specified, the current user is assumed.");
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004710 }
4711
4712 static int onShellCommand(Shell shell, String cmd) {
4713 if (cmd == null) {
4714 return shell.handleDefaultCommands(cmd);
4715 }
4716 PrintWriter pw = shell.getOutPrintWriter();
4717 PrintWriter err = shell.getErrPrintWriter();
4718 try {
4719 switch (cmd) {
4720 case "set": {
4721 int res = shell.parseUserPackageOp(true, err);
4722 if (res < 0) {
4723 return res;
4724 }
4725 String modeStr = shell.getNextArg();
4726 if (modeStr == null) {
4727 err.println("Error: Mode not specified.");
4728 return -1;
4729 }
4730
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004731 final int mode = shell.strModeToMode(modeStr, err);
4732 if (mode < 0) {
4733 return -1;
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004734 }
4735
Svet Ganovd563e932019-04-14 13:07:41 -07004736 if (!shell.targetsUid && shell.packageName != null) {
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004737 shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
4738 mode);
Svet Ganovd563e932019-04-14 13:07:41 -07004739 } else if (shell.targetsUid && shell.packageName != null) {
4740 try {
4741 final int uid = shell.mInternal.mContext.getPackageManager()
Abhijeet Kaur62477e52020-01-29 18:55:49 +00004742 .getPackageUidAsUser(shell.packageName, shell.userId);
Svet Ganovd563e932019-04-14 13:07:41 -07004743 shell.mInterface.setUidMode(shell.op, uid, mode);
4744 } catch (PackageManager.NameNotFoundException e) {
4745 return -1;
4746 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004747 } else {
4748 shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
4749 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004750 return 0;
4751 }
4752 case "get": {
4753 int res = shell.parseUserPackageOp(false, err);
4754 if (res < 0) {
4755 return res;
4756 }
4757
Eugene Suslae4ee2c22018-11-05 12:23:30 -08004758 List<AppOpsManager.PackageOps> ops = new ArrayList<>();
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004759 if (shell.packageName != null) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08004760 // Uid mode overrides package mode, so make sure it's also reported
4761 List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
4762 shell.packageUid,
4763 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
4764 if (r != null) {
4765 ops.addAll(r);
4766 }
4767 r = shell.mInterface.getOpsForPackage(
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004768 shell.packageUid, shell.packageName,
4769 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
Eugene Suslae4ee2c22018-11-05 12:23:30 -08004770 if (r != null) {
4771 ops.addAll(r);
4772 }
Dianne Hackbornc7214a32017-04-11 13:32:47 -07004773 } else {
4774 ops = shell.mInterface.getUidOps(
4775 shell.nonpackageUid,
4776 shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
4777 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004778 if (ops == null || ops.size() <= 0) {
4779 pw.println("No operations.");
Svet Ganov82f09bc2018-01-12 22:08:40 -08004780 if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004781 pw.println("Default mode: " + AppOpsManager.modeToName(
Svet Ganov82f09bc2018-01-12 22:08:40 -08004782 AppOpsManager.opToDefaultMode(shell.op)));
4783 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004784 return 0;
4785 }
4786 final long now = System.currentTimeMillis();
4787 for (int i=0; i<ops.size(); i++) {
Eugene Suslae4ee2c22018-11-05 12:23:30 -08004788 AppOpsManager.PackageOps packageOps = ops.get(i);
4789 if (packageOps.getPackageName() == null) {
4790 pw.print("Uid mode: ");
4791 }
4792 List<AppOpsManager.OpEntry> entries = packageOps.getOps();
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004793 for (int j=0; j<entries.size(); j++) {
4794 AppOpsManager.OpEntry ent = entries.get(j);
4795 pw.print(AppOpsManager.opToName(ent.getOp()));
4796 pw.print(": ");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004797 pw.print(AppOpsManager.modeToName(ent.getMode()));
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004798 if (shell.attributionTag == null) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004799 if (ent.getLastAccessTime(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004800 pw.print("; time=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004801 TimeUtils.formatDuration(
4802 now - ent.getLastAccessTime(OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004803 pw.print(" ago");
4804 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004805 if (ent.getLastRejectTime(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004806 pw.print("; rejectTime=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004807 TimeUtils.formatDuration(
4808 now - ent.getLastRejectTime(OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004809 pw.print(" ago");
4810 }
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004811 if (ent.isRunning()) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004812 pw.print(" (running)");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004813 } else if (ent.getLastDuration(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004814 pw.print("; duration=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004815 TimeUtils.formatDuration(ent.getLastDuration(OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004816 }
4817 } else {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004818 final AppOpsManager.AttributedOpEntry attributionEnt =
4819 ent.getAttributedOpEntries().get(shell.attributionTag);
4820 if (attributionEnt != null) {
4821 if (attributionEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004822 pw.print("; time=");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004823 TimeUtils.formatDuration(
4824 now - attributionEnt.getLastAccessTime(
4825 OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004826 pw.print(" ago");
4827 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004828 if (attributionEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004829 pw.print("; rejectTime=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004830 TimeUtils.formatDuration(
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004831 now - attributionEnt.getLastRejectTime(
4832 OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004833 pw.print(" ago");
4834 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004835 if (attributionEnt.isRunning()) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004836 pw.print(" (running)");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004837 } else if (attributionEnt.getLastDuration(OP_FLAGS_ALL)
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004838 != -1) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004839 pw.print("; duration=");
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08004840 TimeUtils.formatDuration(
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004841 attributionEnt.getLastDuration(OP_FLAGS_ALL), pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004842 }
4843 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004844 }
4845 pw.println();
4846 }
4847 }
4848 return 0;
4849 }
Dianne Hackborne91f3e72016-03-25 18:48:15 -07004850 case "query-op": {
4851 int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
4852 if (res < 0) {
4853 return res;
4854 }
4855 List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
4856 new int[] {shell.op});
4857 if (ops == null || ops.size() <= 0) {
4858 pw.println("No operations.");
4859 return 0;
4860 }
4861 for (int i=0; i<ops.size(); i++) {
4862 final AppOpsManager.PackageOps pkg = ops.get(i);
4863 boolean hasMatch = false;
4864 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
4865 for (int j=0; j<entries.size(); j++) {
4866 AppOpsManager.OpEntry ent = entries.get(j);
4867 if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
4868 hasMatch = true;
4869 break;
4870 }
4871 }
4872 if (hasMatch) {
4873 pw.println(pkg.getPackageName());
4874 }
4875 }
4876 return 0;
4877 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004878 case "reset": {
4879 String packageName = null;
4880 int userId = UserHandle.USER_CURRENT;
4881 for (String argument; (argument = shell.getNextArg()) != null;) {
4882 if ("--user".equals(argument)) {
4883 String userStr = shell.getNextArgRequired();
4884 userId = UserHandle.parseUserArg(userStr);
4885 } else {
4886 if (packageName == null) {
4887 packageName = argument;
4888 } else {
4889 err.println("Error: Unsupported argument: " + argument);
4890 return -1;
4891 }
4892 }
4893 }
4894
4895 if (userId == UserHandle.USER_CURRENT) {
4896 userId = ActivityManager.getCurrentUser();
4897 }
4898
4899 shell.mInterface.resetAllModes(userId, packageName);
4900 pw.print("Reset all modes for: ");
4901 if (userId == UserHandle.USER_ALL) {
4902 pw.print("all users");
4903 } else {
4904 pw.print("user "); pw.print(userId);
4905 }
4906 pw.print(", ");
4907 if (packageName == null) {
4908 pw.println("all packages");
4909 } else {
4910 pw.print("package "); pw.println(packageName);
4911 }
4912 return 0;
4913 }
4914 case "write-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07004915 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
4916 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004917 long token = Binder.clearCallingIdentity();
4918 try {
4919 synchronized (shell.mInternal) {
4920 shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
4921 }
4922 shell.mInternal.writeState();
4923 pw.println("Current settings written.");
4924 } finally {
4925 Binder.restoreCallingIdentity(token);
4926 }
4927 return 0;
4928 }
4929 case "read-settings": {
Dianne Hackbornd5254412018-05-11 18:02:58 -07004930 shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
4931 Binder.getCallingUid(), -1);
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004932 long token = Binder.clearCallingIdentity();
4933 try {
4934 shell.mInternal.readState();
4935 pw.println("Last settings read.");
4936 } finally {
4937 Binder.restoreCallingIdentity(token);
4938 }
4939 return 0;
4940 }
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004941 case "start": {
4942 int res = shell.parseUserPackageOp(true, err);
4943 if (res < 0) {
4944 return res;
4945 }
4946
4947 if (shell.packageName != null) {
Philip P. Moltmann59076d82019-08-19 15:00:40 -07004948 shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004949 shell.packageName, shell.attributionTag, true, true,
Philip P. Moltmannda554e42019-12-20 11:21:02 -08004950 "appops start shell command");
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004951 } else {
4952 return -1;
4953 }
4954 return 0;
4955 }
4956 case "stop": {
4957 int res = shell.parseUserPackageOp(true, err);
4958 if (res < 0) {
4959 return res;
4960 }
4961
4962 if (shell.packageName != null) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004963 shell.mInterface.finishOperation(shell.mToken, shell.op, shell.packageUid,
4964 shell.packageName, shell.attributionTag);
Julia Reynolds6cb5fcc2018-02-27 17:33:52 -05004965 } else {
4966 return -1;
4967 }
4968 return 0;
4969 }
Dianne Hackborn268e4e32015-11-18 16:29:56 -08004970 default:
4971 return shell.handleDefaultCommands(cmd);
4972 }
4973 } catch (RemoteException e) {
4974 pw.println("Remote exception: " + e);
4975 }
4976 return -1;
4977 }
4978
4979 private void dumpHelp(PrintWriter pw) {
4980 pw.println("AppOps service (appops) dump options:");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07004981 pw.println(" -h");
4982 pw.println(" Print this help text.");
4983 pw.println(" --op [OP]");
4984 pw.println(" Limit output to data associated with the given app op code.");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07004985 pw.println(" --mode [MODE]");
4986 pw.println(" Limit output to data associated with the given app op mode.");
4987 pw.println(" --package [PACKAGE]");
4988 pw.println(" Limit output to data associated with the given package name.");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004989 pw.println(" --attributionTag [attributionTag]");
4990 pw.println(" Limit output to data associated with the given attribution tag.");
Dianne Hackborn125dc532019-01-09 13:31:48 -08004991 pw.println(" --watchers");
4992 pw.println(" Only output the watcher sections.");
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07004993 }
4994
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004995 private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08004996 @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now,
4997 @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08004998 final int numAttributions = op.mAttributions.size();
4999 for (int i = 0; i < numAttributions; i++) {
5000 if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(
5001 op.mAttributions.keyAt(i), filterAttributionTag)) {
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005002 continue;
5003 }
5004
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005005 pw.print(prefix + op.mAttributions.keyAt(i) + "=[\n");
5006 dumpStatesLocked(pw, nowElapsed, op, op.mAttributions.keyAt(i), now, sdf, date,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07005007 prefix + " ");
5008 pw.print(prefix + "]\n");
5009 }
5010 }
Svet Ganovaf189e32019-02-15 18:45:29 -08005011
Philip P. Moltmann59076d82019-08-19 15:00:40 -07005012 private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005013 @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf,
Philip P. Moltmann59076d82019-08-19 15:00:40 -07005014 @NonNull Date date, @NonNull String prefix) {
5015
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005016 final AttributedOpEntry entry = op.createSingleAttributionEntryLocked(
5017 attributionTag).getAttributedOpEntries().get(attributionTag);
Svet Ganovaf189e32019-02-15 18:45:29 -08005018
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08005019 final ArraySet<Long> keys = entry.collectKeys();
Svet Ganovaf189e32019-02-15 18:45:29 -08005020
5021 final int keyCount = keys.size();
5022 for (int k = 0; k < keyCount; k++) {
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08005023 final long key = keys.valueAt(k);
Svet Ganovaf189e32019-02-15 18:45:29 -08005024
5025 final int uidState = AppOpsManager.extractUidStateFromKey(key);
5026 final int flags = AppOpsManager.extractFlagsFromKey(key);
5027
Philip P. Moltmann49bd9e12019-11-26 15:18:16 -08005028 final long accessTime = entry.getLastAccessTime(uidState, uidState, flags);
5029 final long rejectTime = entry.getLastRejectTime(uidState, uidState, flags);
5030 final long accessDuration = entry.getLastDuration(uidState, uidState, flags);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005031 final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
5032
5033 String proxyPkg = null;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005034 String proxyAttributionTag = null;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005035 int proxyUid = Process.INVALID_UID;
5036 if (proxy != null) {
5037 proxyPkg = proxy.getPackageName();
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005038 proxyAttributionTag = proxy.getAttributionTag();
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005039 proxyUid = proxy.getUid();
5040 }
Svet Ganovaf189e32019-02-15 18:45:29 -08005041
5042 if (accessTime > 0) {
5043 pw.print(prefix);
5044 pw.print("Access: ");
5045 pw.print(AppOpsManager.keyToString(key));
5046 pw.print(" ");
5047 date.setTime(accessTime);
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07005048 pw.print(sdf.format(date));
5049 pw.print(" (");
Svet Ganovaf189e32019-02-15 18:45:29 -08005050 TimeUtils.formatDuration(accessTime - now, pw);
5051 pw.print(")");
5052 if (accessDuration > 0) {
5053 pw.print(" duration=");
5054 TimeUtils.formatDuration(accessDuration, pw);
5055 }
5056 if (proxyUid >= 0) {
5057 pw.print(" proxy[");
5058 pw.print("uid=");
5059 pw.print(proxyUid);
5060 pw.print(", pkg=");
5061 pw.print(proxyPkg);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005062 pw.print(", attributionTag=");
5063 pw.print(proxyAttributionTag);
Svet Ganovaf189e32019-02-15 18:45:29 -08005064 pw.print("]");
5065 }
5066 pw.println();
5067 }
5068
5069 if (rejectTime > 0) {
5070 pw.print(prefix);
5071 pw.print("Reject: ");
5072 pw.print(AppOpsManager.keyToString(key));
5073 date.setTime(rejectTime);
5074 pw.print(sdf.format(date));
5075 pw.print(" (");
5076 TimeUtils.formatDuration(rejectTime - now, pw);
5077 pw.print(")");
5078 if (proxyUid >= 0) {
5079 pw.print(" proxy[");
5080 pw.print("uid=");
5081 pw.print(proxyUid);
5082 pw.print(", pkg=");
5083 pw.print(proxyPkg);
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005084 pw.print(", attributionTag=");
5085 pw.print(proxyAttributionTag);
Svet Ganovaf189e32019-02-15 18:45:29 -08005086 pw.print("]");
5087 }
5088 pw.println();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07005089 }
5090 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07005091
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005092 final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
5093 if (attributedOp.isRunning()) {
Philip P. Moltmanne6ece902020-01-02 13:31:10 -08005094 long earliestElapsedTime = Long.MAX_VALUE;
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005095 long maxNumStarts = 0;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005096 int numInProgressEvents = attributedOp.mInProgressEvents.size();
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005097 for (int i = 0; i < numInProgressEvents; i++) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005098 InProgressStartOpEvent event = attributedOp.mInProgressEvents.valueAt(i);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005099
Philip P. Moltmannd8c0bda2019-12-19 19:55:35 -08005100 earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005101 maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts);
5102 }
5103
Philip P. Moltmann59076d82019-08-19 15:00:40 -07005104 pw.print(prefix + "Running start at: ");
Philip P. Moltmanne6ece902020-01-02 13:31:10 -08005105 TimeUtils.formatDuration(nowElapsed - earliestElapsedTime, pw);
Philip P. Moltmann59076d82019-08-19 15:00:40 -07005106 pw.println();
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005107
5108 if (maxNumStarts > 1) {
5109 pw.print(prefix + "startNesting=");
5110 pw.println(maxNumStarts);
5111 }
Philip P. Moltmann59076d82019-08-19 15:00:40 -07005112 }
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07005113 }
5114
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005115 @Override
5116 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06005117 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005118
Svet Ganov8455ba22019-01-02 13:05:56 -08005119 int dumpOp = OP_NONE;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005120 String dumpPackage = null;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005121 String dumpAttributionTag = null;
Svet Ganov8455ba22019-01-02 13:05:56 -08005122 int dumpUid = Process.INVALID_UID;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005123 int dumpMode = -1;
Dianne Hackborn125dc532019-01-09 13:31:48 -08005124 boolean dumpWatchers = false;
Nate Myren697650b2020-01-23 13:25:06 -08005125 // TODO ntmyren: Remove the dumpHistory and dumpFilter
Svet Ganovaf189e32019-02-15 18:45:29 -08005126 boolean dumpHistory = false;
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005127 @HistoricalOpsRequestFilter int dumpFilter = 0;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005128
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07005129 if (args != null) {
5130 for (int i=0; i<args.length; i++) {
5131 String arg = args[i];
5132 if ("-h".equals(arg)) {
5133 dumpHelp(pw);
5134 return;
Tim Kilbourn8f1ea832015-08-26 15:07:37 -07005135 } else if ("-a".equals(arg)) {
5136 // dump all data
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005137 } else if ("--op".equals(arg)) {
5138 i++;
5139 if (i >= args.length) {
5140 pw.println("No argument for --op option");
5141 return;
5142 }
5143 dumpOp = Shell.strOpToOp(args[i], pw);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005144 dumpFilter |= FILTER_BY_OP_NAMES;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005145 if (dumpOp < 0) {
5146 return;
5147 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005148 } else if ("--package".equals(arg)) {
5149 i++;
5150 if (i >= args.length) {
5151 pw.println("No argument for --package option");
5152 return;
5153 }
5154 dumpPackage = args[i];
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005155 dumpFilter |= FILTER_BY_PACKAGE_NAME;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005156 try {
5157 dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
5158 PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
5159 0);
5160 } catch (RemoteException e) {
5161 }
5162 if (dumpUid < 0) {
5163 pw.println("Unknown package: " + dumpPackage);
5164 return;
5165 }
5166 dumpUid = UserHandle.getAppId(dumpUid);
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005167 dumpFilter |= FILTER_BY_UID;
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005168 } else if ("--attributionTag".equals(arg)) {
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005169 i++;
5170 if (i >= args.length) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005171 pw.println("No argument for --attributionTag option");
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005172 return;
5173 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005174 dumpAttributionTag = args[i];
5175 dumpFilter |= FILTER_BY_ATTRIBUTION_TAG;
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005176 } else if ("--mode".equals(arg)) {
5177 i++;
5178 if (i >= args.length) {
5179 pw.println("No argument for --mode option");
5180 return;
5181 }
5182 dumpMode = Shell.strModeToMode(args[i], pw);
5183 if (dumpMode < 0) {
5184 return;
5185 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08005186 } else if ("--watchers".equals(arg)) {
5187 dumpWatchers = true;
Dianne Hackborn4d34bb82015-08-07 18:26:38 -07005188 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
5189 pw.println("Unknown option: " + arg);
5190 return;
5191 } else {
5192 pw.println("Unknown command: " + arg);
5193 return;
5194 }
5195 }
5196 }
5197
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005198 synchronized (this) {
5199 pw.println("Current AppOps Service state:");
Svet Ganovaf189e32019-02-15 18:45:29 -08005200 if (!dumpHistory && !dumpWatchers) {
5201 mConstants.dump(pw);
5202 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005203 pw.println();
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08005204 final long now = System.currentTimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07005205 final long nowElapsed = SystemClock.elapsedRealtime();
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005206 final long nowUptime = SystemClock.uptimeMillis();
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07005207 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
5208 final Date date = new Date();
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005209 boolean needSep = false;
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005210 if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers
5211 && !dumpHistory) {
Dianne Hackbornd5254412018-05-11 18:02:58 -07005212 pw.println(" Profile owners:");
5213 for (int poi = 0; poi < mProfileOwners.size(); poi++) {
5214 pw.print(" User #");
5215 pw.print(mProfileOwners.keyAt(poi));
5216 pw.print(": ");
5217 UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
5218 pw.println();
5219 }
5220 pw.println();
5221 }
Svet Ganovaf189e32019-02-15 18:45:29 -08005222 if (mOpModeWatchers.size() > 0 && !dumpHistory) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005223 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005224 for (int i=0; i<mOpModeWatchers.size(); i++) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005225 if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
5226 continue;
5227 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005228 boolean printedOpHeader = false;
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005229 ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005230 for (int j=0; j<callbacks.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005231 final ModeCallback cb = callbacks.valueAt(j);
Dianne Hackborn125dc532019-01-09 13:31:48 -08005232 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005233 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
5234 continue;
5235 }
5236 needSep = true;
5237 if (!printedHeader) {
5238 pw.println(" Op mode watchers:");
5239 printedHeader = true;
5240 }
5241 if (!printedOpHeader) {
5242 pw.print(" Op ");
5243 pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
5244 pw.println(":");
5245 printedOpHeader = true;
5246 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005247 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005248 pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005249 }
5250 }
5251 }
Svet Ganovaf189e32019-02-15 18:45:29 -08005252 if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005253 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005254 for (int i=0; i<mPackageModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005255 if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
5256 continue;
5257 }
5258 needSep = true;
5259 if (!printedHeader) {
5260 pw.println(" Package mode watchers:");
5261 printedHeader = true;
5262 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005263 pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
5264 pw.println(":");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005265 ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005266 for (int j=0; j<callbacks.size(); j++) {
5267 pw.print(" #"); pw.print(j); pw.print(": ");
Dianne Hackborn68d76552017-02-27 15:32:03 -08005268 pw.println(callbacks.valueAt(j));
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005269 }
5270 }
5271 }
Svet Ganovaf189e32019-02-15 18:45:29 -08005272 if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005273 boolean printedHeader = false;
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005274 for (int i=0; i<mModeWatchers.size(); i++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005275 final ModeCallback cb = mModeWatchers.valueAt(i);
Dianne Hackborn125dc532019-01-09 13:31:48 -08005276 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005277 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
5278 continue;
5279 }
5280 needSep = true;
5281 if (!printedHeader) {
5282 pw.println(" All op mode watchers:");
5283 printedHeader = true;
5284 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07005285 pw.print(" ");
5286 pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005287 pw.print(": "); pw.println(cb);
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005288 }
5289 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005290 if (mActiveWatchers.size() > 0 && dumpMode < 0) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005291 needSep = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005292 boolean printedHeader = false;
Philip P. Moltmannba136462019-05-21 10:20:38 -07005293 for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
5294 final SparseArray<ActiveCallback> activeWatchers =
5295 mActiveWatchers.valueAt(watcherNum);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005296 if (activeWatchers.size() <= 0) {
5297 continue;
5298 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005299 final ActiveCallback cb = activeWatchers.valueAt(0);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005300 if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
5301 continue;
5302 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08005303 if (dumpPackage != null
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005304 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
5305 continue;
5306 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005307 if (!printedHeader) {
5308 pw.println(" All op active watchers:");
5309 printedHeader = true;
5310 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07005311 pw.print(" ");
5312 pw.print(Integer.toHexString(System.identityHashCode(
Philip P. Moltmannba136462019-05-21 10:20:38 -07005313 mActiveWatchers.keyAt(watcherNum))));
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07005314 pw.println(" ->");
5315 pw.print(" [");
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005316 final int opCount = activeWatchers.size();
Philip P. Moltmannba136462019-05-21 10:20:38 -07005317 for (int opNum = 0; opNum < opCount; opNum++) {
5318 if (opNum > 0) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005319 pw.print(' ');
5320 }
Philip P. Moltmannba136462019-05-21 10:20:38 -07005321 pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
5322 if (opNum < opCount - 1) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005323 pw.print(',');
5324 }
5325 }
Dianne Hackborn3b563fc2018-04-16 17:17:14 -07005326 pw.println("]");
5327 pw.print(" ");
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005328 pw.println(cb);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005329 }
5330 }
Adam Bookatz182862e2020-04-27 21:58:22 -07005331 if (mStartedWatchers.size() > 0 && dumpMode < 0) {
5332 needSep = true;
5333 boolean printedHeader = false;
5334
5335 final int watchersSize = mStartedWatchers.size();
5336 for (int watcherNum = 0; watcherNum < watchersSize; watcherNum++) {
5337 final SparseArray<StartedCallback> startedWatchers =
5338 mStartedWatchers.valueAt(watcherNum);
5339 if (startedWatchers.size() <= 0) {
5340 continue;
5341 }
5342
5343 final StartedCallback cb = startedWatchers.valueAt(0);
5344 if (dumpOp >= 0 && startedWatchers.indexOfKey(dumpOp) < 0) {
5345 continue;
5346 }
5347
5348 if (dumpPackage != null
5349 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
5350 continue;
5351 }
5352
5353 if (!printedHeader) {
5354 pw.println(" All op started watchers:");
5355 printedHeader = true;
5356 }
5357
5358 pw.print(" ");
5359 pw.print(Integer.toHexString(System.identityHashCode(
5360 mStartedWatchers.keyAt(watcherNum))));
5361 pw.println(" ->");
5362
5363 pw.print(" [");
5364 final int opCount = startedWatchers.size();
5365 for (int opNum = 0; opNum < opCount; opNum++) {
5366 if (opNum > 0) {
5367 pw.print(' ');
5368 }
5369
5370 pw.print(AppOpsManager.opToName(startedWatchers.keyAt(opNum)));
5371 if (opNum < opCount - 1) {
5372 pw.print(',');
5373 }
5374 }
5375 pw.println("]");
5376
5377 pw.print(" ");
5378 pw.println(cb);
5379 }
5380 }
Svet Ganovb3d2ae22018-12-17 22:06:15 -08005381 if (mNotedWatchers.size() > 0 && dumpMode < 0) {
5382 needSep = true;
5383 boolean printedHeader = false;
Adam Bookatzb80bf4e2020-04-22 17:59:29 -07005384 for (int watcherNum = 0; watcherNum < mNotedWatchers.size(); watcherNum++) {
5385 final SparseArray<NotedCallback> notedWatchers =
5386 mNotedWatchers.valueAt(watcherNum);
Svet Ganovb3d2ae22018-12-17 22:06:15 -08005387 if (notedWatchers.size() <= 0) {
5388 continue;
5389 }
5390 final NotedCallback cb = notedWatchers.valueAt(0);
5391 if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
5392 continue;
5393 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08005394 if (dumpPackage != null
Svet Ganovb3d2ae22018-12-17 22:06:15 -08005395 && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
5396 continue;
5397 }
5398 if (!printedHeader) {
5399 pw.println(" All op noted watchers:");
5400 printedHeader = true;
5401 }
5402 pw.print(" ");
5403 pw.print(Integer.toHexString(System.identityHashCode(
Adam Bookatzb80bf4e2020-04-22 17:59:29 -07005404 mNotedWatchers.keyAt(watcherNum))));
Svet Ganovb3d2ae22018-12-17 22:06:15 -08005405 pw.println(" ->");
5406 pw.print(" [");
5407 final int opCount = notedWatchers.size();
Adam Bookatzb80bf4e2020-04-22 17:59:29 -07005408 for (int opNum = 0; opNum < opCount; opNum++) {
5409 if (opNum > 0) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08005410 pw.print(' ');
5411 }
Adam Bookatzb80bf4e2020-04-22 17:59:29 -07005412 pw.print(AppOpsManager.opToName(notedWatchers.keyAt(opNum)));
5413 if (opNum < opCount - 1) {
Svet Ganovb3d2ae22018-12-17 22:06:15 -08005414 pw.print(',');
5415 }
5416 }
5417 pw.println("]");
5418 pw.print(" ");
5419 pw.println(cb);
5420 }
5421 }
Yin-Chia Yeh51d85162019-08-06 15:31:39 -07005422 if (mAudioRestrictionManager.hasActiveRestrictions() && dumpOp < 0
5423 && dumpPackage != null && dumpMode < 0 && !dumpWatchers && !dumpWatchers) {
5424 needSep = mAudioRestrictionManager.dump(pw) | needSep ;
John Spurlock1af30c72014-03-10 08:33:35 -04005425 }
Dianne Hackborne98f5db2013-07-17 17:23:25 -07005426 if (needSep) {
5427 pw.println();
5428 }
Svet Ganov2af57082015-07-30 08:44:20 -07005429 for (int i=0; i<mUidStates.size(); i++) {
5430 UidState uidState = mUidStates.valueAt(i);
Hai Zhang93540ca2019-09-28 00:04:18 +00005431 final SparseIntArray opModes = uidState.opModes;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005432 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
5433
Svet Ganovaf189e32019-02-15 18:45:29 -08005434 if (dumpWatchers || dumpHistory) {
Dianne Hackborn125dc532019-01-09 13:31:48 -08005435 continue;
5436 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005437 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
Hai Zhang93540ca2019-09-28 00:04:18 +00005438 boolean hasOp = dumpOp < 0 || (uidState.opModes != null
5439 && uidState.opModes.indexOfKey(dumpOp) >= 0);
Philip P. Moltmannceffd592020-01-02 12:05:15 -08005440 boolean hasPackage = dumpPackage == null || dumpUid == mUidStates.keyAt(i);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005441 boolean hasMode = dumpMode < 0;
Hai Zhang93540ca2019-09-28 00:04:18 +00005442 if (!hasMode && opModes != null) {
5443 for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
5444 if (opModes.valueAt(opi) == dumpMode) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005445 hasMode = true;
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005446 }
5447 }
5448 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005449 if (pkgOps != null) {
5450 for (int pkgi = 0;
Svet Ganov8455ba22019-01-02 13:05:56 -08005451 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
5452 pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005453 Ops ops = pkgOps.valueAt(pkgi);
5454 if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
5455 hasOp = true;
5456 }
5457 if (!hasMode) {
5458 for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
5459 if (ops.valueAt(opi).mode == dumpMode) {
5460 hasMode = true;
5461 }
5462 }
5463 }
5464 if (!hasPackage && dumpPackage.equals(ops.packageName)) {
5465 hasPackage = true;
5466 }
5467 }
5468 }
5469 if (uidState.foregroundOps != null && !hasOp) {
5470 if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
5471 hasOp = true;
5472 }
5473 }
5474 if (!hasOp || !hasPackage || !hasMode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005475 continue;
5476 }
5477 }
Svet Ganov2af57082015-07-30 08:44:20 -07005478
5479 pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
Dianne Hackborncd1f30b2018-04-23 17:38:09 -07005480 pw.print(" state=");
Svet Ganovaf189e32019-02-15 18:45:29 -08005481 pw.println(AppOpsManager.getUidStateName(uidState.state));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005482 if (uidState.state != uidState.pendingState) {
5483 pw.print(" pendingState=");
Svet Ganovaf189e32019-02-15 18:45:29 -08005484 pw.println(AppOpsManager.getUidStateName(uidState.pendingState));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005485 }
Hui Yu26969322019-08-21 14:56:35 -07005486 pw.print(" capability=");
5487 pw.println(uidState.capability);
5488 if (uidState.capability != uidState.pendingCapability) {
5489 pw.print(" pendingCapability=");
5490 pw.println(uidState.pendingCapability);
5491 }
Hui Yu48032682020-04-10 14:18:51 -07005492 pw.print(" appWidgetVisible=");
5493 pw.println(uidState.appWidgetVisible);
5494 if (uidState.appWidgetVisible != uidState.pendingAppWidgetVisible) {
5495 pw.print(" pendingAppWidgetVisible=");
5496 pw.println(uidState.pendingAppWidgetVisible);
5497 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005498 if (uidState.pendingStateCommitTime != 0) {
5499 pw.print(" pendingStateCommitTime=");
Dianne Hackborn9fb93502018-06-18 12:29:44 -07005500 TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005501 pw.println();
5502 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005503 if (uidState.foregroundOps != null && (dumpMode < 0
5504 || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005505 pw.println(" foregroundOps:");
5506 for (int j = 0; j < uidState.foregroundOps.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005507 if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
5508 continue;
5509 }
5510 pw.print(" ");
5511 pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
5512 pw.print(": ");
5513 pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005514 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005515 pw.print(" hasForegroundWatchers=");
5516 pw.println(uidState.hasForegroundWatchers);
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005517 }
Svet Ganovee438d42017-01-19 18:04:38 -08005518 needSep = true;
Svet Ganov2af57082015-07-30 08:44:20 -07005519
Hai Zhang93540ca2019-09-28 00:04:18 +00005520 if (opModes != null) {
5521 final int opModeCount = opModes.size();
5522 for (int j = 0; j < opModeCount; j++) {
5523 final int code = opModes.keyAt(j);
5524 final int mode = opModes.valueAt(j);
5525 if (dumpOp >= 0 && dumpOp != code) {
5526 continue;
5527 }
5528 if (dumpMode >= 0 && dumpMode != mode) {
5529 continue;
5530 }
5531 pw.print(" "); pw.print(AppOpsManager.opToName(code));
5532 pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
Svet Ganov2af57082015-07-30 08:44:20 -07005533 }
5534 }
5535
Svet Ganov2af57082015-07-30 08:44:20 -07005536 if (pkgOps == null) {
5537 continue;
5538 }
5539
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005540 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005541 final Ops ops = pkgOps.valueAt(pkgi);
5542 if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
5543 continue;
5544 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005545 boolean printedPackage = false;
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005546 for (int j=0; j<ops.size(); j++) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005547 final Op op = ops.valueAt(j);
Svet Ganovaf189e32019-02-15 18:45:29 -08005548 final int opCode = op.op;
5549 if (dumpOp >= 0 && dumpOp != opCode) {
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005550 continue;
5551 }
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005552 if (dumpMode >= 0 && dumpMode != op.mode) {
5553 continue;
5554 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005555 if (!printedPackage) {
5556 pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
5557 printedPackage = true;
5558 }
Svet Ganovaf189e32019-02-15 18:45:29 -08005559 pw.print(" "); pw.print(AppOpsManager.opToName(opCode));
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005560 pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
Svet Ganovaf189e32019-02-15 18:45:29 -08005561 final int switchOp = AppOpsManager.opToSwitch(opCode);
5562 if (switchOp != opCode) {
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005563 pw.print(" / switch ");
5564 pw.print(AppOpsManager.opToName(switchOp));
5565 final Op switchObj = ops.get(switchOp);
Svet Ganovaf189e32019-02-15 18:45:29 -08005566 int mode = switchObj != null ? switchObj.mode
5567 : AppOpsManager.opToDefaultMode(switchOp);
Dianne Hackborn65a4f252018-05-08 17:30:48 -07005568 pw.print("="); pw.print(AppOpsManager.modeToName(mode));
5569 }
Dianne Hackborn2378a4a2018-04-26 13:46:22 -07005570 pw.println("): ");
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005571 dumpStatesLocked(pw, dumpAttributionTag, dumpFilter, nowElapsed, op, now,
5572 sdf, date, " ");
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005573 }
5574 }
5575 }
Svet Ganovee438d42017-01-19 18:04:38 -08005576 if (needSep) {
5577 pw.println();
5578 }
5579
5580 final int userRestrictionCount = mOpUserRestrictions.size();
5581 for (int i = 0; i < userRestrictionCount; i++) {
5582 IBinder token = mOpUserRestrictions.keyAt(i);
5583 ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
Dianne Hackborn125dc532019-01-09 13:31:48 -08005584 boolean printedTokenHeader = false;
5585
Svet Ganovaf189e32019-02-15 18:45:29 -08005586 if (dumpMode >= 0 || dumpWatchers || dumpHistory) {
Dianne Hackborn125dc532019-01-09 13:31:48 -08005587 continue;
5588 }
Svet Ganovee438d42017-01-19 18:04:38 -08005589
5590 final int restrictionCount = restrictionState.perUserRestrictions != null
5591 ? restrictionState.perUserRestrictions.size() : 0;
Dianne Hackborn125dc532019-01-09 13:31:48 -08005592 if (restrictionCount > 0 && dumpPackage == null) {
5593 boolean printedOpsHeader = false;
Svet Ganovee438d42017-01-19 18:04:38 -08005594 for (int j = 0; j < restrictionCount; j++) {
5595 int userId = restrictionState.perUserRestrictions.keyAt(j);
5596 boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
5597 if (restrictedOps == null) {
5598 continue;
5599 }
Dianne Hackborn125dc532019-01-09 13:31:48 -08005600 if (dumpOp >= 0 && (dumpOp >= restrictedOps.length
5601 || !restrictedOps[dumpOp])) {
5602 continue;
5603 }
5604 if (!printedTokenHeader) {
5605 pw.println(" User restrictions for token " + token + ":");
5606 printedTokenHeader = true;
5607 }
5608 if (!printedOpsHeader) {
5609 pw.println(" Restricted ops:");
5610 printedOpsHeader = true;
5611 }
Svet Ganovee438d42017-01-19 18:04:38 -08005612 StringBuilder restrictedOpsValue = new StringBuilder();
5613 restrictedOpsValue.append("[");
5614 final int restrictedOpCount = restrictedOps.length;
5615 for (int k = 0; k < restrictedOpCount; k++) {
5616 if (restrictedOps[k]) {
5617 if (restrictedOpsValue.length() > 1) {
5618 restrictedOpsValue.append(", ");
5619 }
5620 restrictedOpsValue.append(AppOpsManager.opToName(k));
5621 }
5622 }
5623 restrictedOpsValue.append("]");
5624 pw.print(" "); pw.print("user: "); pw.print(userId);
5625 pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
5626 }
5627 }
5628
5629 final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
5630 ? restrictionState.perUserExcludedPackages.size() : 0;
Dianne Hackborn125dc532019-01-09 13:31:48 -08005631 if (excludedPackageCount > 0 && dumpOp < 0) {
5632 boolean printedPackagesHeader = false;
Svet Ganovee438d42017-01-19 18:04:38 -08005633 for (int j = 0; j < excludedPackageCount; j++) {
5634 int userId = restrictionState.perUserExcludedPackages.keyAt(j);
5635 String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
Dianne Hackborn125dc532019-01-09 13:31:48 -08005636 if (packageNames == null) {
5637 continue;
5638 }
5639 boolean hasPackage;
5640 if (dumpPackage != null) {
5641 hasPackage = false;
5642 for (String pkg : packageNames) {
5643 if (dumpPackage.equals(pkg)) {
5644 hasPackage = true;
5645 break;
5646 }
5647 }
5648 } else {
5649 hasPackage = true;
5650 }
5651 if (!hasPackage) {
5652 continue;
5653 }
5654 if (!printedTokenHeader) {
5655 pw.println(" User restrictions for token " + token + ":");
5656 printedTokenHeader = true;
5657 }
5658 if (!printedPackagesHeader) {
5659 pw.println(" Excluded packages:");
5660 printedPackagesHeader = true;
5661 }
Svet Ganovee438d42017-01-19 18:04:38 -08005662 pw.print(" "); pw.print("user: "); pw.print(userId);
5663 pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
5664 }
5665 }
5666 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005667 }
Svet Ganov8455ba22019-01-02 13:05:56 -08005668
5669 // Must not hold the appops lock
Svet Ganovaf189e32019-02-15 18:45:29 -08005670 if (dumpHistory && !dumpWatchers) {
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005671 mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp,
Philip P. Moltmann4aacd712020-01-03 12:32:20 -08005672 dumpFilter);
Svet Ganovaf189e32019-02-15 18:45:29 -08005673 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08005674 }
John Spurlock1af30c72014-03-10 08:33:35 -04005675
Jason Monk62062992014-05-06 09:55:28 -04005676 @Override
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005677 public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
Jason Monk62062992014-05-06 09:55:28 -04005678 checkSystemUid("setUserRestrictions");
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00005679 Objects.requireNonNull(restrictions);
5680 Objects.requireNonNull(token);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005681 for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
Jason Monk62062992014-05-06 09:55:28 -04005682 String restriction = AppOpsManager.opToRestriction(i);
Suprabh Shukla64e0dcb2016-05-24 16:23:11 -07005683 if (restriction != null) {
5684 setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
5685 userHandle, null);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07005686 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005687 }
5688 }
5689
5690 @Override
Ruben Brunk29931bc2016-03-11 00:24:26 -08005691 public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
5692 String[] exceptionPackages) {
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005693 if (Binder.getCallingPid() != Process.myPid()) {
5694 mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
5695 Binder.getCallingPid(), Binder.getCallingUid(), null);
5696 }
5697 if (userHandle != UserHandle.getCallingUserId()) {
5698 if (mContext.checkCallingOrSelfPermission(Manifest.permission
5699 .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
5700 && mContext.checkCallingOrSelfPermission(Manifest.permission
5701 .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
5702 throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
5703 + " INTERACT_ACROSS_USERS to interact cross user ");
Jason Monk62062992014-05-06 09:55:28 -04005704 }
5705 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005706 verifyIncomingOp(code);
Daulet Zhanguzin9bd13702020-01-03 09:44:10 +00005707 Objects.requireNonNull(token);
Ruben Brunk29931bc2016-03-11 00:24:26 -08005708 setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005709 }
5710
5711 private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
Ruben Brunk29931bc2016-03-11 00:24:26 -08005712 int userHandle, String[] exceptionPackages) {
Svet Ganov442ed572016-08-17 17:29:43 -07005713 synchronized (AppOpsService.this) {
5714 ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
5715
5716 if (restrictionState == null) {
5717 try {
5718 restrictionState = new ClientRestrictionState(token);
5719 } catch (RemoteException e) {
5720 return;
5721 }
5722 mOpUserRestrictions.put(token, restrictionState);
Ruben Brunk29931bc2016-03-11 00:24:26 -08005723 }
Svet Ganov442ed572016-08-17 17:29:43 -07005724
5725 if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005726 mHandler.sendMessage(PooledLambda.obtainMessage(
Svet Ganov3a95f832018-03-23 17:44:30 -07005727 AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
Svet Ganov442ed572016-08-17 17:29:43 -07005728 }
5729
5730 if (restrictionState.isDefault()) {
5731 mOpUserRestrictions.remove(token);
5732 restrictionState.destroy();
5733 }
Ruben Brunk29931bc2016-03-11 00:24:26 -08005734 }
Julia Reynoldsbb21c252016-04-05 16:01:49 -04005735 }
5736
Svet Ganov3a95f832018-03-23 17:44:30 -07005737 private void notifyWatchersOfChange(int code, int uid) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005738 final ArraySet<ModeCallback> clonedCallbacks;
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005739 synchronized (this) {
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005740 ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005741 if (callbacks == null) {
5742 return;
5743 }
Dianne Hackborn68d76552017-02-27 15:32:03 -08005744 clonedCallbacks = new ArraySet<>(callbacks);
Svet Ganov9cea80cd2016-02-16 11:47:00 -08005745 }
5746
Svet Ganov3a95f832018-03-23 17:44:30 -07005747 notifyOpChanged(clonedCallbacks, code, uid, null);
Jason Monk62062992014-05-06 09:55:28 -04005748 }
5749
5750 @Override
5751 public void removeUser(int userHandle) throws RemoteException {
5752 checkSystemUid("removeUser");
Svet Ganov442ed572016-08-17 17:29:43 -07005753 synchronized (AppOpsService.this) {
5754 final int tokenCount = mOpUserRestrictions.size();
5755 for (int i = tokenCount - 1; i >= 0; i--) {
5756 ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
5757 opRestrictions.removeUser(userHandle);
5758 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07005759 removeUidsForUserLocked(userHandle);
5760 }
5761 }
5762
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005763 @Override
5764 public boolean isOperationActive(int code, int uid, String packageName) {
Svet Ganovf7b47252018-02-26 11:11:27 -08005765 if (Binder.getCallingUid() != uid) {
5766 if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
5767 != PackageManager.PERMISSION_GRANTED) {
5768 return false;
5769 }
5770 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005771 verifyIncomingOp(code);
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005772 final String resolvedPackageName = resolvePackageName(uid, packageName);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005773 if (resolvedPackageName == null) {
5774 return false;
5775 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005776 // TODO moltmann: Allow to check for attribution op activeness
Svetoslav Ganov2d20fb42018-02-08 15:52:10 -08005777 synchronized (AppOpsService.this) {
Philip P. Moltmannad787aa2020-03-10 09:49:22 -07005778 Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false);
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005779 if (pkgOps == null) {
5780 return false;
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005781 }
Philip P. Moltmann6c6403e2019-12-09 10:08:29 -08005782
5783 Op op = pkgOps.get(code);
5784 if (op == null) {
5785 return false;
5786 }
5787
5788 return op.isRunning();
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005789 }
Jeff Sharkey35e46d22017-06-09 10:01:20 -06005790 }
5791
Svet Ganov8455ba22019-01-02 13:05:56 -08005792 @Override
5793 public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
5794 long baseSnapshotInterval, int compressionStep) {
5795 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5796 "setHistoryParameters");
5797 // Must not hold the appops lock
5798 mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
5799 }
5800
5801 @Override
5802 public void offsetHistory(long offsetMillis) {
5803 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5804 "offsetHistory");
5805 // Must not hold the appops lock
5806 mHistoricalRegistry.offsetHistory(offsetMillis);
5807 }
5808
5809 @Override
5810 public void addHistoricalOps(HistoricalOps ops) {
5811 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5812 "addHistoricalOps");
5813 // Must not hold the appops lock
5814 mHistoricalRegistry.addHistoricalOps(ops);
5815 }
5816
5817 @Override
5818 public void resetHistoryParameters() {
5819 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5820 "resetHistoryParameters");
5821 // Must not hold the appops lock
5822 mHistoricalRegistry.resetHistoryParameters();
5823 }
5824
5825 @Override
5826 public void clearHistory() {
5827 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
5828 "clearHistory");
5829 // Must not hold the appops lock
5830 mHistoricalRegistry.clearHistory();
5831 }
5832
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005833 /**
5834 * Report runtime access to AppOp together with message (including stack trace)
5835 *
5836 * @param packageName The package which reported the op
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005837 * @param notedAppOp contains code of op and attributionTag provided by developer
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005838 * @param message Message describing AppOp access (can be stack trace)
5839 *
5840 * @return Config for future sampling to reduce amount of reporting
5841 */
5842 @Override
5843 public MessageSamplingConfig reportRuntimeAppOpAccessMessageAndGetConfig(
5844 String packageName, SyncNotedAppOp notedAppOp, String message) {
5845 int uid = Binder.getCallingUid();
5846 Objects.requireNonNull(packageName);
5847 synchronized (this) {
Stanislav Zholnin4c323852020-03-04 18:03:24 +00005848 switchPackageIfBootTimeOrRarelyUsedLocked(packageName);
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005849 if (!packageName.equals(mSampledPackage)) {
5850 return new MessageSamplingConfig(OP_NONE, 0,
5851 Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
5852 }
5853
5854 Objects.requireNonNull(notedAppOp);
5855 Objects.requireNonNull(message);
5856
5857 reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName,
5858 AppOpsManager.strOpToOp(notedAppOp.getOp()),
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005859 notedAppOp.getAttributionTag(), message);
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005860
5861 return new MessageSamplingConfig(mSampledAppOpCode, mAcceptableLeftDistance,
5862 Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
5863 }
5864 }
5865
5866 /**
5867 * Report runtime access to AppOp together with message (entry point for reporting
5868 * asynchronous access)
5869 * @param uid Uid of the package which reported the op
5870 * @param packageName The package which reported the op
5871 * @param opCode Code of AppOp
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005872 * @param attributionTag FeautreId of AppOp reported
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005873 * @param message Message describing AppOp access (can be stack trace)
5874 */
5875 private void reportRuntimeAppOpAccessMessageAsyncLocked(int uid,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005876 @NonNull String packageName, int opCode, @Nullable String attributionTag,
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005877 @NonNull String message) {
Stanislav Zholnin4c323852020-03-04 18:03:24 +00005878 switchPackageIfBootTimeOrRarelyUsedLocked(packageName);
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005879 if (!Objects.equals(mSampledPackage, packageName)) {
5880 return;
5881 }
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005882 reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, opCode, attributionTag,
5883 message);
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005884 }
5885
5886 /**
5887 * Decides whether reported message is within the range of watched AppOps and picks it for
5888 * reporting uniformly at random across all received messages.
5889 */
5890 private void reportRuntimeAppOpAccessMessageInternalLocked(int uid,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005891 @NonNull String packageName, int opCode, @Nullable String attributionTag,
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005892 @NonNull String message) {
5893 int newLeftDistance = AppOpsManager.leftCircularDistance(opCode,
5894 mSampledAppOpCode, _NUM_OP);
5895
5896 if (mAcceptableLeftDistance < newLeftDistance) {
5897 return;
5898 }
5899
5900 if (mAcceptableLeftDistance > newLeftDistance) {
5901 mAcceptableLeftDistance = newLeftDistance;
5902 mMessagesCollectedCount = 0.0f;
5903 }
5904
5905 mMessagesCollectedCount += 1.0f;
5906 if (ThreadLocalRandom.current().nextFloat() <= 1.0f / mMessagesCollectedCount) {
5907 mCollectedRuntimePermissionMessage = new RuntimeAppOpAccessMessage(uid, opCode,
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -08005908 packageName, attributionTag, message, mSamplingStrategy);
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005909 }
5910 return;
5911 }
5912
5913 /** Pulls current AppOps access report and resamples package and app op to watch */
5914 @Override
5915 public @Nullable RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage() {
5916 mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
5917 Binder.getCallingPid(), Binder.getCallingUid(), null);
5918 RuntimeAppOpAccessMessage result;
5919 List<String> packageNames = getPackageNamesForSampling();
5920 synchronized (this) {
5921 result = mCollectedRuntimePermissionMessage;
5922 resamplePackageAndAppOpLocked(packageNames);
5923 }
5924 return result;
5925 }
5926
5927 /**
5928 * Checks if package is in the list of rarely used package and starts watching the new package
Stanislav Zholnin4c323852020-03-04 18:03:24 +00005929 * to collect incoming message or if collection is happening in first minutes since boot.
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005930 * @param packageName
5931 */
Stanislav Zholnin4c323852020-03-04 18:03:24 +00005932 private void switchPackageIfBootTimeOrRarelyUsedLocked(@NonNull String packageName) {
5933 if (mSampledPackage == null) {
Stanislav Zholnin15492092020-04-19 06:21:36 +01005934 if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
Stanislav Zholnin4c323852020-03-04 18:03:24 +00005935 mSamplingStrategy = SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
5936 resampleAppOpForPackageLocked(packageName);
5937 }
5938 } else if (mRarelyUsedPackages.contains(packageName)) {
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005939 mRarelyUsedPackages.remove(packageName);
5940 if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
Muhammad Qureshi317061a2020-03-02 13:15:51 -08005941 mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED;
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005942 resampleAppOpForPackageLocked(packageName);
5943 }
5944 }
5945 }
5946
5947 /** Resamples package and appop to watch from the list provided. */
5948 private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) {
5949 if (!packageNames.isEmpty()) {
Muhammad Qureshi317061a2020-03-02 13:15:51 -08005950 mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM;
Stanislav Zholnin90516b92020-01-20 14:03:06 +00005951 resampleAppOpForPackageLocked(packageNames.get(
5952 ThreadLocalRandom.current().nextInt(packageNames.size())));
5953 }
5954 }
5955
5956 /** Resamples appop for the chosen package and initializes sampling state */
5957 private void resampleAppOpForPackageLocked(@NonNull String packageName) {
5958 mMessagesCollectedCount = 0.0f;
5959 mSampledAppOpCode = ThreadLocalRandom.current().nextInt(_NUM_OP);
5960 mAcceptableLeftDistance = _NUM_OP;
5961 mSampledPackage = packageName;
5962 mCollectedRuntimePermissionMessage = null;
5963 }
5964
5965 /**
5966 * Creates list of rarely used packages - packages which were not used over last week or
5967 * which declared but did not use permissions over last week.
5968 * */
5969 private void initializeRarelyUsedPackagesList(@NonNull ArraySet<String> candidates) {
5970 AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
5971 List<String> runtimeAppOpsList = getRuntimeAppOpsList();
5972 AppOpsManager.HistoricalOpsRequest histOpsRequest =
5973 new AppOpsManager.HistoricalOpsRequest.Builder(
5974 Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(),
5975 Long.MAX_VALUE).setOpNames(runtimeAppOpsList).setFlags(
5976 OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED).build();
5977 appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR,
5978 new Consumer<HistoricalOps>() {
5979 @Override
5980 public void accept(HistoricalOps histOps) {
5981 int uidCount = histOps.getUidCount();
5982 for (int uidIdx = 0; uidIdx < uidCount; uidIdx++) {
5983 final AppOpsManager.HistoricalUidOps uidOps = histOps.getUidOpsAt(
5984 uidIdx);
5985 int pkgCount = uidOps.getPackageCount();
5986 for (int pkgIdx = 0; pkgIdx < pkgCount; pkgIdx++) {
5987 String packageName = uidOps.getPackageOpsAt(
5988 pkgIdx).getPackageName();
5989 if (!candidates.contains(packageName)) {
5990 continue;
5991 }
5992 AppOpsManager.HistoricalPackageOps packageOps =
5993 uidOps.getPackageOpsAt(pkgIdx);
5994 if (packageOps.getOpCount() != 0) {
5995 candidates.remove(packageName);
5996 }
5997 }
5998 }
5999 synchronized (this) {
Stanislav Zholnin4c323852020-03-04 18:03:24 +00006000 int numPkgs = mRarelyUsedPackages.size();
6001 for (int i = 0; i < numPkgs; i++) {
6002 candidates.add(mRarelyUsedPackages.valueAt(i));
6003 }
Stanislav Zholnin90516b92020-01-20 14:03:06 +00006004 mRarelyUsedPackages = candidates;
6005 }
6006 }
6007 });
6008 }
6009
6010 /** List of app ops related to runtime permissions */
6011 private List<String> getRuntimeAppOpsList() {
6012 ArrayList<String> result = new ArrayList();
6013 for (int i = 0; i < _NUM_OP; i++) {
6014 if (shouldCollectNotes(i)) {
6015 result.add(opToPublicName(i));
6016 }
6017 }
6018 return result;
6019 }
6020
6021 /** Returns list of packages to be used for package sampling */
6022 private @NonNull List<String> getPackageNamesForSampling() {
6023 List<String> packageNames = new ArrayList<>();
6024 PackageManagerInternal packageManagerInternal = LocalServices.getService(
6025 PackageManagerInternal.class);
6026 PackageList packages = packageManagerInternal.getPackageList();
6027 for (String packageName : packages.getPackageNames()) {
6028 PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName,
6029 PackageManager.GET_PERMISSIONS, Process.myUid(), mContext.getUserId());
6030 if (isSamplingTarget(pkg)) {
6031 packageNames.add(pkg.packageName);
6032 }
6033 }
6034 return packageNames;
6035 }
6036
6037 /** Checks whether package should be included in sampling pool */
6038 private boolean isSamplingTarget(@Nullable PackageInfo pkg) {
6039 if (pkg == null) {
6040 return false;
6041 }
Stanislav Zholnin90516b92020-01-20 14:03:06 +00006042 String[] requestedPermissions = pkg.requestedPermissions;
6043 if (requestedPermissions == null) {
6044 return false;
6045 }
6046 for (String permission : requestedPermissions) {
6047 PermissionInfo permissionInfo;
6048 try {
6049 permissionInfo = mContext.getPackageManager().getPermissionInfo(permission, 0);
6050 } catch (PackageManager.NameNotFoundException ignored) {
6051 continue;
6052 }
6053 if (permissionInfo.getProtection() == PROTECTION_DANGEROUS) {
6054 return true;
6055 }
6056 }
6057 return false;
6058 }
6059
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07006060 private void removeUidsForUserLocked(int userHandle) {
6061 for (int i = mUidStates.size() - 1; i >= 0; --i) {
6062 final int uid = mUidStates.keyAt(i);
6063 if (UserHandle.getUserId(uid) == userHandle) {
6064 mUidStates.removeAt(i);
6065 }
Svet Ganov9cea80cd2016-02-16 11:47:00 -08006066 }
6067 }
6068
Jason Monk62062992014-05-06 09:55:28 -04006069 private void checkSystemUid(String function) {
6070 int uid = Binder.getCallingUid();
6071 if (uid != Process.SYSTEM_UID) {
6072 throw new SecurityException(function + " must by called by the system");
6073 }
6074 }
6075
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00006076 private static String resolvePackageName(int uid, String packageName) {
Svet Ganov82f09bc2018-01-12 22:08:40 -08006077 if (uid == Process.ROOT_UID) {
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00006078 return "root";
6079 } else if (uid == Process.SHELL_UID) {
6080 return "com.android.shell";
Svet Ganov82f09bc2018-01-12 22:08:40 -08006081 } else if (uid == Process.MEDIA_UID) {
6082 return "media";
6083 } else if (uid == Process.AUDIOSERVER_UID) {
6084 return "audioserver";
6085 } else if (uid == Process.CAMERASERVER_UID) {
6086 return "cameraserver";
Svetoslav Ganovf73adb62016-03-29 01:07:06 +00006087 } else if (uid == Process.SYSTEM_UID && packageName == null) {
6088 return "android";
6089 }
6090 return packageName;
6091 }
6092
Svet Ganov82f09bc2018-01-12 22:08:40 -08006093 private static int resolveUid(String packageName) {
6094 if (packageName == null) {
6095 return -1;
6096 }
6097 switch (packageName) {
6098 case "root":
6099 return Process.ROOT_UID;
6100 case "shell":
6101 return Process.SHELL_UID;
6102 case "media":
6103 return Process.MEDIA_UID;
6104 case "audioserver":
6105 return Process.AUDIOSERVER_UID;
6106 case "cameraserver":
6107 return Process.CAMERASERVER_UID;
6108 }
6109 return -1;
6110 }
6111
Svet Ganov2af57082015-07-30 08:44:20 -07006112 private static String[] getPackagesForUid(int uid) {
Svet Ganovf3807aa2015-08-02 10:09:56 -07006113 String[] packageNames = null;
Philip P. Moltmann159d98b2018-12-20 08:30:53 -08006114
6115 // Very early during boot the package manager is not yet or not yet fully started. At this
6116 // time there are no packages yet.
6117 if (AppGlobals.getPackageManager() != null) {
6118 try {
6119 packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
6120 } catch (RemoteException e) {
6121 /* ignore - local call */
6122 }
Svet Ganov2af57082015-07-30 08:44:20 -07006123 }
Svet Ganovf3807aa2015-08-02 10:09:56 -07006124 if (packageNames == null) {
6125 return EmptyArray.STRING;
6126 }
6127 return packageNames;
Svet Ganov2af57082015-07-30 08:44:20 -07006128 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07006129
6130 private final class ClientRestrictionState implements DeathRecipient {
6131 private final IBinder token;
6132 SparseArray<boolean[]> perUserRestrictions;
6133 SparseArray<String[]> perUserExcludedPackages;
6134
6135 public ClientRestrictionState(IBinder token)
6136 throws RemoteException {
6137 token.linkToDeath(this, 0);
6138 this.token = token;
6139 }
6140
6141 public boolean setRestriction(int code, boolean restricted,
6142 String[] excludedPackages, int userId) {
6143 boolean changed = false;
6144
6145 if (perUserRestrictions == null && restricted) {
6146 perUserRestrictions = new SparseArray<>();
6147 }
6148
Philip P. Moltmanne683f192017-06-23 14:05:04 -07006149 int[] users;
6150 if (userId == UserHandle.USER_ALL) {
6151 List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07006152
Philip P. Moltmanne683f192017-06-23 14:05:04 -07006153 users = new int[liveUsers.size()];
6154 for (int i = 0; i < liveUsers.size(); i++) {
6155 users[i] = liveUsers.get(i).id;
6156 }
6157 } else {
6158 users = new int[]{userId};
6159 }
6160
6161 if (perUserRestrictions != null) {
6162 int numUsers = users.length;
6163
6164 for (int i = 0; i < numUsers; i++) {
6165 int thisUserId = users[i];
6166
6167 boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
6168 if (userRestrictions == null && restricted) {
6169 userRestrictions = new boolean[AppOpsManager._NUM_OP];
6170 perUserRestrictions.put(thisUserId, userRestrictions);
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07006171 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07006172 if (userRestrictions != null && userRestrictions[code] != restricted) {
6173 userRestrictions[code] = restricted;
6174 if (!restricted && isDefault(userRestrictions)) {
6175 perUserRestrictions.remove(thisUserId);
6176 userRestrictions = null;
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07006177 }
6178 changed = true;
6179 }
Philip P. Moltmanne683f192017-06-23 14:05:04 -07006180
6181 if (userRestrictions != null) {
6182 final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
6183 if (perUserExcludedPackages == null && !noExcludedPackages) {
6184 perUserExcludedPackages = new SparseArray<>();
6185 }
6186 if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
6187 perUserExcludedPackages.get(thisUserId))) {
6188 if (noExcludedPackages) {
6189 perUserExcludedPackages.remove(thisUserId);
6190 if (perUserExcludedPackages.size() <= 0) {
6191 perUserExcludedPackages = null;
6192 }
6193 } else {
6194 perUserExcludedPackages.put(thisUserId, excludedPackages);
6195 }
6196 changed = true;
6197 }
6198 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07006199 }
6200 }
6201
6202 return changed;
6203 }
6204
6205 public boolean hasRestriction(int restriction, String packageName, int userId) {
6206 if (perUserRestrictions == null) {
6207 return false;
6208 }
6209 boolean[] restrictions = perUserRestrictions.get(userId);
6210 if (restrictions == null) {
6211 return false;
6212 }
6213 if (!restrictions[restriction]) {
6214 return false;
6215 }
6216 if (perUserExcludedPackages == null) {
6217 return true;
6218 }
6219 String[] perUserExclusions = perUserExcludedPackages.get(userId);
6220 if (perUserExclusions == null) {
6221 return true;
6222 }
6223 return !ArrayUtils.contains(perUserExclusions, packageName);
6224 }
6225
6226 public void removeUser(int userId) {
6227 if (perUserExcludedPackages != null) {
6228 perUserExcludedPackages.remove(userId);
6229 if (perUserExcludedPackages.size() <= 0) {
6230 perUserExcludedPackages = null;
6231 }
6232 }
Sudheer Shankabc2fadd2016-09-27 17:36:39 -07006233 if (perUserRestrictions != null) {
6234 perUserRestrictions.remove(userId);
6235 if (perUserRestrictions.size() <= 0) {
6236 perUserRestrictions = null;
6237 }
6238 }
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07006239 }
6240
6241 public boolean isDefault() {
6242 return perUserRestrictions == null || perUserRestrictions.size() <= 0;
6243 }
6244
6245 @Override
6246 public void binderDied() {
6247 synchronized (AppOpsService.this) {
6248 mOpUserRestrictions.remove(token);
6249 if (perUserRestrictions == null) {
6250 return;
6251 }
6252 final int userCount = perUserRestrictions.size();
6253 for (int i = 0; i < userCount; i++) {
6254 final boolean[] restrictions = perUserRestrictions.valueAt(i);
6255 final int restrictionCount = restrictions.length;
6256 for (int j = 0; j < restrictionCount; j++) {
6257 if (restrictions[j]) {
6258 final int changedCode = j;
Svet Ganov3a95f832018-03-23 17:44:30 -07006259 mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
Svetoslav Ganova8bbd762016-05-13 17:08:16 -07006260 }
6261 }
6262 }
6263 destroy();
6264 }
6265 }
6266
6267 public void destroy() {
6268 token.unlinkToDeath(this, 0);
6269 }
6270
6271 private boolean isDefault(boolean[] array) {
6272 if (ArrayUtils.isEmpty(array)) {
6273 return true;
6274 }
6275 for (boolean value : array) {
6276 if (value) {
6277 return false;
6278 }
6279 }
6280 return true;
6281 }
6282 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07006283
6284 private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
6285 @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
6286 synchronized (AppOpsService.this) {
6287 mProfileOwners = owners;
6288 }
6289 }
Hui Yu88910de2019-12-16 14:35:27 -08006290
6291 @Override
6292 public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames,
6293 boolean visible) {
6294 AppOpsService.this.updateAppWidgetVisibility(uidPackageNames, visible);
6295 }
Hai Zhangf4ef0392020-02-03 14:49:35 -08006296
6297 @Override
Hai Zhang8846aaa2020-02-13 15:19:54 -08006298 public void setUidModeFromPermissionPolicy(int code, int uid, int mode,
6299 @Nullable IAppOpsCallback callback) {
6300 setUidMode(code, uid, mode, callback);
Hai Zhangf4ef0392020-02-03 14:49:35 -08006301 }
6302
6303 @Override
Hai Zhang8846aaa2020-02-13 15:19:54 -08006304 public void setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName,
6305 int mode, @Nullable IAppOpsCallback callback) {
6306 setMode(code, uid, packageName, mode, callback);
Hai Zhangf4ef0392020-02-03 14:49:35 -08006307 }
Dianne Hackbornd5254412018-05-11 18:02:58 -07006308 }
David Cheung2ead9662020-02-19 16:11:06 -08006309
6310
6311 /**
6312 * Async task for writing note op stack trace, op code, package name and version to file
6313 * More specifically, writes all the collected ops from {@link #mNoteOpCallerStacktraces}
6314 */
6315 private void writeNoteOps() {
6316 synchronized (this) {
6317 mWriteNoteOpsScheduled = false;
6318 }
6319 synchronized (mNoteOpCallerStacktracesFile) {
6320 try (FileWriter writer = new FileWriter(mNoteOpCallerStacktracesFile)) {
6321 int numTraces = mNoteOpCallerStacktraces.size();
6322 for (int i = 0; i < numTraces; i++) {
6323 // Writing json formatted string into file
6324 writer.write(mNoteOpCallerStacktraces.valueAt(i).asJson());
6325 // Comma separation, so we can wrap the entire log as a JSON object
6326 // when all results are collected
6327 writer.write(",");
6328 }
6329 } catch (IOException e) {
6330 Slog.w(TAG, "Failed to load opsValidation file for FileWriter", e);
6331 }
6332 }
6333 }
6334
6335 /**
6336 * This class represents a NoteOp Trace object amd contains the necessary fields that will
6337 * be written to file to use for permissions data validation in JSON format
6338 */
6339 @Immutable
6340 static class NoteOpTrace {
6341 static final String STACKTRACE = "stackTrace";
6342 static final String OP = "op";
6343 static final String PACKAGENAME = "packageName";
6344 static final String VERSION = "version";
6345
6346 private final @NonNull String mStackTrace;
6347 private final int mOp;
6348 private final @Nullable String mPackageName;
6349 private final long mVersion;
6350
6351 /**
6352 * Initialize a NoteOp object using a JSON object containing the necessary fields
6353 *
6354 * @param jsonTrace JSON object represented as a string
6355 *
6356 * @return NoteOpTrace object initialized with JSON fields
6357 */
6358 static NoteOpTrace fromJson(String jsonTrace) {
6359 try {
6360 // Re-add closing bracket which acted as a delimiter by the reader
6361 JSONObject obj = new JSONObject(jsonTrace.concat("}"));
6362 return new NoteOpTrace(obj.getString(STACKTRACE), obj.getInt(OP),
6363 obj.getString(PACKAGENAME), obj.getLong(VERSION));
6364 } catch (JSONException e) {
6365 // Swallow error, only meant for logging ops, should not affect flow of the code
6366 Slog.e(TAG, "Error constructing NoteOpTrace object "
6367 + "JSON trace format incorrect", e);
6368 return null;
6369 }
6370 }
6371
6372 NoteOpTrace(String stackTrace, int op, String packageName, long version) {
6373 mStackTrace = stackTrace;
6374 mOp = op;
6375 mPackageName = packageName;
6376 mVersion = version;
6377 }
6378
6379 @Override
6380 public boolean equals(Object o) {
6381 if (this == o) return true;
6382 if (o == null || getClass() != o.getClass()) return false;
6383 NoteOpTrace that = (NoteOpTrace) o;
6384 return mOp == that.mOp
6385 && mVersion == that.mVersion
6386 && mStackTrace.equals(that.mStackTrace)
6387 && Objects.equals(mPackageName, that.mPackageName);
6388 }
6389
6390 @Override
6391 public int hashCode() {
6392 return Objects.hash(mStackTrace, mOp, mPackageName, mVersion);
6393 }
6394
6395 /**
6396 * The object is formatted as a JSON object and returned as a String
6397 *
6398 * @return JSON formatted string
6399 */
6400 public String asJson() {
6401 return "{"
6402 + "\"" + STACKTRACE + "\":\"" + mStackTrace.replace("\n", "\\n")
6403 + '\"' + ",\"" + OP + "\":" + mOp
6404 + ",\"" + PACKAGENAME + "\":\"" + mPackageName + '\"'
6405 + ",\"" + VERSION + "\":" + mVersion
6406 + '}';
6407 }
6408 }
6409
6410 /**
6411 * Collects noteOps, noteProxyOps and startOps from AppOpsManager and writes it into a file
6412 * which will be used for permissions data validation, the given parameters to this method
6413 * will be logged in json format
6414 *
6415 * @param stackTrace stacktrace from the most recent call in AppOpsManager
6416 * @param op op code
6417 * @param packageName package making call
6418 * @param version android version for this call
6419 */
6420 @Override
6421 public void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName,
6422 long version) {
6423 if (!AppOpsManager.NOTE_OP_COLLECTION_ENABLED) {
6424 return;
6425 }
6426
6427 Objects.requireNonNull(stackTrace);
6428 Preconditions.checkArgument(op >= 0);
6429 Preconditions.checkArgument(op < AppOpsManager._NUM_OP);
6430 Objects.requireNonNull(version);
6431
6432 NoteOpTrace noteOpTrace = new NoteOpTrace(stackTrace, op, packageName, version);
6433
6434 boolean noteOpSetWasChanged;
6435 synchronized (this) {
6436 noteOpSetWasChanged = mNoteOpCallerStacktraces.add(noteOpTrace);
6437 if (noteOpSetWasChanged && !mWriteNoteOpsScheduled) {
6438 mWriteNoteOpsScheduled = true;
6439 mHandler.postDelayed(PooledLambda.obtainRunnable((that) -> {
6440 AsyncTask.execute(() -> {
6441 that.writeNoteOps();
6442 });
6443 }, this), 2500);
6444 }
6445 }
6446 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -08006447}