blob: a85d6d8380451fb3b69933f7a0ca954616f4f4a0 [file] [log] [blame]
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001/*
2 * Copyright (C) 2016 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 */
16package com.android.server.pm;
17
Makoto Onuki7001a612016-05-27 13:24:28 -070018import android.annotation.IntDef;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080019import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.annotation.UserIdInt;
Makoto Onuki55046222016-03-08 10:49:47 -080022import android.app.ActivityManager;
Makoto Onuki33525d22016-08-03 15:45:24 -070023import android.app.ActivityManagerInternal;
Makoto Onuki0acbb142016-03-22 17:02:57 -070024import android.app.AppGlobals;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070025import android.app.IUidObserver;
Makoto Onukiac042502016-05-20 16:39:42 -070026import android.app.usage.UsageStatsManagerInternal;
Sunny Goyal87a563e2017-01-01 19:42:45 -080027import android.appwidget.AppWidgetProviderInfo;
Makoto Onuki4e6cef42016-07-13 16:14:01 -070028import android.content.BroadcastReceiver;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080029import android.content.ComponentName;
30import android.content.Context;
31import android.content.Intent;
Makoto Onuki4e6cef42016-07-13 16:14:01 -070032import android.content.IntentFilter;
Makoto Onuki2d895c32016-12-02 15:48:40 -080033import android.content.IntentSender;
34import android.content.IntentSender.SendIntentException;
Makoto Onuki22fcc682016-05-17 14:52:19 -070035import android.content.pm.ActivityInfo;
Makoto Onuki0acbb142016-03-22 17:02:57 -070036import android.content.pm.ApplicationInfo;
37import android.content.pm.IPackageManager;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080038import android.content.pm.IShortcutService;
39import android.content.pm.LauncherApps;
40import android.content.pm.LauncherApps.ShortcutQuery;
Makoto Onuki0acbb142016-03-22 17:02:57 -070041import android.content.pm.PackageInfo;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080042import android.content.pm.PackageManager;
Makoto Onuki2d5b4652016-03-11 16:09:54 -080043import android.content.pm.PackageManagerInternal;
Todd Kennedy0eb97382017-10-03 16:57:22 -070044import android.content.pm.PackageManager.NameNotFoundException;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080045import android.content.pm.ParceledListSlice;
Makoto Onuki2d5b4652016-03-11 16:09:54 -080046import android.content.pm.ResolveInfo;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080047import android.content.pm.ShortcutInfo;
48import android.content.pm.ShortcutServiceInternal;
49import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
Makoto Onuki2d895c32016-12-02 15:48:40 -080050import android.content.pm.UserInfo;
Makoto Onuki157b1622016-06-02 16:13:10 -070051import android.content.res.Resources;
Makoto Onuki22fcc682016-05-17 14:52:19 -070052import android.content.res.XmlResourceParser;
Makoto Onuki55046222016-03-08 10:49:47 -080053import android.graphics.Bitmap;
54import android.graphics.Bitmap.CompressFormat;
Makoto Onuki55046222016-03-08 10:49:47 -080055import android.graphics.Canvas;
56import android.graphics.RectF;
Hyunyoung Song47037462017-05-08 16:51:43 -070057import android.graphics.drawable.AdaptiveIconDrawable;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080058import android.graphics.drawable.Icon;
Makoto Onuki4e6cef42016-07-13 16:14:01 -070059import android.net.Uri;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080060import android.os.Binder;
Makoto Onuki33663282016-08-22 16:19:04 -070061import android.os.Build;
Sunny Goyal4ad6b572017-02-28 11:11:51 -080062import android.os.Bundle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080063import android.os.Environment;
Makoto Onuki2e210c42016-03-30 08:30:36 -070064import android.os.FileUtils;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080065import android.os.Handler;
Makoto Onuki4e6cef42016-07-13 16:14:01 -070066import android.os.LocaleList;
Makoto Onukiaa8b94a2016-03-17 13:14:05 -070067import android.os.Looper;
Makoto Onuki55046222016-03-08 10:49:47 -080068import android.os.ParcelFileDescriptor;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080069import android.os.PersistableBundle;
70import android.os.Process;
71import android.os.RemoteException;
72import android.os.ResultReceiver;
Makoto Onuki55046222016-03-08 10:49:47 -080073import android.os.SELinux;
Makoto Onukib08790c2016-06-23 14:05:46 -070074import android.os.ServiceManager;
Dianne Hackborn354736e2016-08-22 17:00:05 -070075import android.os.ShellCallback;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080076import android.os.ShellCommand;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070077import android.os.SystemClock;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080078import android.os.UserHandle;
Makoto Onukicdc78f72016-03-21 15:47:52 -070079import android.os.UserManager;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080080import android.text.TextUtils;
81import android.text.format.Time;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080082import android.util.ArraySet;
83import android.util.AtomicFile;
Makoto Onuki4362a662016-03-08 18:59:09 -080084import android.util.KeyValueListParser;
Makoto Onukiac042502016-05-20 16:39:42 -070085import android.util.Log;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080086import android.util.Slog;
87import android.util.SparseArray;
Makoto Onuki02f338e2016-07-29 09:40:40 -070088import android.util.SparseBooleanArray;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070089import android.util.SparseIntArray;
90import android.util.SparseLongArray;
Makoto Onuki55046222016-03-08 10:49:47 -080091import android.util.TypedValue;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080092import android.util.Xml;
Makoto Onukib08790c2016-06-23 14:05:46 -070093import android.view.IWindowManager;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080094
95import com.android.internal.annotations.GuardedBy;
96import com.android.internal.annotations.VisibleForTesting;
97import com.android.internal.os.BackgroundThread;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060098import com.android.internal.util.DumpUtils;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080099import com.android.internal.util.FastXmlSerializer;
100import com.android.internal.util.Preconditions;
101import com.android.server.LocalServices;
Makoto Onuki84d59342018-02-02 09:22:38 -0800102import com.android.server.StatLogger;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800103import com.android.server.SystemService;
Makoto Onukid99c6f02016-03-28 11:02:54 -0700104import com.android.server.pm.ShortcutUser.PackageWithUser;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800105
106import libcore.io.IoUtils;
107
Makoto Onuki76269922016-07-15 14:58:54 -0700108import org.json.JSONArray;
109import org.json.JSONException;
110import org.json.JSONObject;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800111import org.xmlpull.v1.XmlPullParser;
112import org.xmlpull.v1.XmlPullParserException;
113import org.xmlpull.v1.XmlSerializer;
114
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700115import java.io.BufferedInputStream;
116import java.io.BufferedOutputStream;
117import java.io.ByteArrayInputStream;
118import java.io.ByteArrayOutputStream;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800119import java.io.File;
120import java.io.FileDescriptor;
121import java.io.FileInputStream;
122import java.io.FileNotFoundException;
123import java.io.FileOutputStream;
124import java.io.IOException;
Makoto Onuki55046222016-03-08 10:49:47 -0800125import java.io.InputStream;
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700126import java.io.OutputStream;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800127import java.io.PrintWriter;
Makoto Onuki7001a612016-05-27 13:24:28 -0700128import java.lang.annotation.Retention;
129import java.lang.annotation.RetentionPolicy;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800130import java.net.URISyntaxException;
131import java.nio.charset.StandardCharsets;
132import java.util.ArrayList;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700133import java.util.Collections;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800134import java.util.List;
Makoto Onukic51b2872016-05-04 15:24:50 -0700135import java.util.concurrent.atomic.AtomicBoolean;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700136import java.util.function.Consumer;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800137import java.util.function.Predicate;
Makoto Onuki20b82212017-10-04 15:03:50 -0700138import java.util.regex.Pattern;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800139
140/**
141 * TODO:
Makoto Onuki22fcc682016-05-17 14:52:19 -0700142 * - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi.
Makoto Onukib5a012f2016-06-21 11:13:53 -0700143 * -> But TypedValue.applyDimension() doesn't differentiate x and y..?
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800144 *
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700145 * - Detect when already registered instances are passed to APIs again, which might break
Makoto Onukib08790c2016-06-23 14:05:46 -0700146 * internal bitmap handling.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800147 */
148public class ShortcutService extends IShortcutService.Stub {
Makoto Onuki55046222016-03-08 10:49:47 -0800149 static final String TAG = "ShortcutService";
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800150
Makoto Onuki7001a612016-05-27 13:24:28 -0700151 static final boolean DEBUG = false; // STOPSHIP if true
Makoto Onuki41066a62016-03-09 16:18:44 -0800152 static final boolean DEBUG_LOAD = false; // STOPSHIP if true
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700153 static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800154
Makoto Onuki4362a662016-03-08 18:59:09 -0800155 @VisibleForTesting
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700156 static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
Makoto Onuki4362a662016-03-08 18:59:09 -0800157
158 @VisibleForTesting
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700159 static final int DEFAULT_MAX_UPDATES_PER_INTERVAL = 10;
Makoto Onuki4362a662016-03-08 18:59:09 -0800160
161 @VisibleForTesting
162 static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5;
163
164 @VisibleForTesting
165 static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96;
166
167 @VisibleForTesting
168 static final int DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP = 48;
169
170 @VisibleForTesting
171 static final String DEFAULT_ICON_PERSIST_FORMAT = CompressFormat.PNG.name();
172
173 @VisibleForTesting
174 static final int DEFAULT_ICON_PERSIST_QUALITY = 100;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800175
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700176 @VisibleForTesting
177 static final int DEFAULT_SAVE_DELAY_MS = 3000;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800178
179 @VisibleForTesting
180 static final String FILENAME_BASE_STATE = "shortcut_service.xml";
181
182 @VisibleForTesting
183 static final String DIRECTORY_PER_USER = "shortcut_service";
184
185 @VisibleForTesting
Makoto Onuki50a320e2017-05-31 14:38:42 -0700186 static final String DIRECTORY_DUMP = "shortcut_dump";
187
188 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800189 static final String FILENAME_USER_PACKAGES = "shortcuts.xml";
190
Makoto Onuki55046222016-03-08 10:49:47 -0800191 static final String DIRECTORY_BITMAPS = "bitmaps";
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800192
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700193 private static final String TAG_ROOT = "root";
194 private static final String TAG_LAST_RESET_TIME = "last_reset_time";
Makoto Onuki55046222016-03-08 10:49:47 -0800195
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700196 private static final String ATTR_VALUE = "value";
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800197
Makoto Onukib08790c2016-06-23 14:05:46 -0700198 private static final String LAUNCHER_INTENT_CATEGORY = Intent.CATEGORY_LAUNCHER;
199
Makoto Onuki76269922016-07-15 14:58:54 -0700200 private static final String KEY_SHORTCUT = "shortcut";
201 private static final String KEY_LOW_RAM = "lowRam";
202 private static final String KEY_ICON_SIZE = "iconSize";
203
Makoto Onuki2d895c32016-12-02 15:48:40 -0800204 private static final String DUMMY_MAIN_ACTIVITY = "android.__dummy__";
205
Makoto Onuki4362a662016-03-08 18:59:09 -0800206 @VisibleForTesting
207 interface ConfigConstants {
208 /**
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700209 * Key name for the save delay, in milliseconds. (int)
210 */
211 String KEY_SAVE_DELAY_MILLIS = "save_delay_ms";
212
213 /**
Makoto Onuki4362a662016-03-08 18:59:09 -0800214 * Key name for the throttling reset interval, in seconds. (long)
215 */
216 String KEY_RESET_INTERVAL_SEC = "reset_interval_sec";
217
218 /**
219 * Key name for the max number of modifying API calls per app for every interval. (int)
220 */
Makoto Onukib6d35232016-04-04 15:57:17 -0700221 String KEY_MAX_UPDATES_PER_INTERVAL = "max_updates_per_interval";
Makoto Onuki4362a662016-03-08 18:59:09 -0800222
223 /**
224 * Key name for the max icon dimensions in DP, for non-low-memory devices.
225 */
226 String KEY_MAX_ICON_DIMENSION_DP = "max_icon_dimension_dp";
227
228 /**
229 * Key name for the max icon dimensions in DP, for low-memory devices.
230 */
231 String KEY_MAX_ICON_DIMENSION_DP_LOWRAM = "max_icon_dimension_dp_lowram";
232
233 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700234 * Key name for the max dynamic shortcuts per activity. (int)
Makoto Onuki4362a662016-03-08 18:59:09 -0800235 */
236 String KEY_MAX_SHORTCUTS = "max_shortcuts";
237
238 /**
Makoto Onuki41066a62016-03-09 16:18:44 -0800239 * Key name for icon compression quality, 0-100.
Makoto Onuki4362a662016-03-08 18:59:09 -0800240 */
241 String KEY_ICON_QUALITY = "icon_quality";
242
243 /**
244 * Key name for icon compression format: "PNG", "JPEG" or "WEBP"
245 */
246 String KEY_ICON_FORMAT = "icon_format";
247 }
248
Makoto Onuki41066a62016-03-09 16:18:44 -0800249 final Context mContext;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800250
251 private final Object mLock = new Object();
252
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700253 private static List<ResolveInfo> EMPTY_RESOLVE_INFO = new ArrayList<>(0);
254
Mark Renoufe065f7c2016-11-01 11:48:24 -0400255 // Temporarily reverted to anonymous inner class form due to: b/32554459
256 private static Predicate<ResolveInfo> ACTIVITY_NOT_EXPORTED = new Predicate<ResolveInfo>() {
257 public boolean test(ResolveInfo ri) {
258 return !ri.activityInfo.exported;
259 }
260 };
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700261
Mark Renoufe065f7c2016-11-01 11:48:24 -0400262 // Temporarily reverted to anonymous inner class form due to: b/32554459
263 private static Predicate<PackageInfo> PACKAGE_NOT_INSTALLED = new Predicate<PackageInfo>() {
264 public boolean test(PackageInfo pi) {
265 return !isInstalled(pi);
266 }
267 };
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700268
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800269 private final Handler mHandler;
270
271 @GuardedBy("mLock")
272 private final ArrayList<ShortcutChangeListener> mListeners = new ArrayList<>(1);
273
274 @GuardedBy("mLock")
275 private long mRawLastResetTime;
276
277 /**
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -0800278 * User ID -> UserShortcuts
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800279 */
280 @GuardedBy("mLock")
Makoto Onuki31459242016-03-22 11:12:18 -0700281 private final SparseArray<ShortcutUser> mUsers = new SparseArray<>();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800282
283 /**
Makoto Onuki708703b2017-12-11 16:38:11 -0800284 * User ID -> ShortcutNonPersistentUser
285 */
286 @GuardedBy("mLock")
287 private final SparseArray<ShortcutNonPersistentUser> mShortcutNonPersistentUsers =
288 new SparseArray<>();
289
290 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700291 * Max number of dynamic + manifest shortcuts that each application can have at a time.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800292 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700293 private int mMaxShortcuts;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800294
295 /**
Makoto Onukib6d35232016-04-04 15:57:17 -0700296 * Max number of updating API calls that each application can make during the interval.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800297 */
Makoto Onukib6d35232016-04-04 15:57:17 -0700298 int mMaxUpdatesPerInterval;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800299
300 /**
301 * Actual throttling-reset interval. By default it's a day.
302 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800303 private long mResetInterval;
304
Makoto Onuki55046222016-03-08 10:49:47 -0800305 /**
306 * Icon max width/height in pixels.
307 */
308 private int mMaxIconDimension;
309
Makoto Onuki4362a662016-03-08 18:59:09 -0800310 private CompressFormat mIconPersistFormat;
311 private int mIconPersistQuality;
Makoto Onuki55046222016-03-08 10:49:47 -0800312
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700313 private int mSaveDelayMillis;
314
Makoto Onuki0acbb142016-03-22 17:02:57 -0700315 private final IPackageManager mIPackageManager;
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800316 private final PackageManagerInternal mPackageManagerInternal;
Makoto Onukicdc78f72016-03-21 15:47:52 -0700317 private final UserManager mUserManager;
Makoto Onukiac042502016-05-20 16:39:42 -0700318 private final UsageStatsManagerInternal mUsageStatsManagerInternal;
Makoto Onuki33525d22016-08-03 15:45:24 -0700319 private final ActivityManagerInternal mActivityManagerInternal;
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800320
Makoto Onuki2d895c32016-12-02 15:48:40 -0800321 private final ShortcutRequestPinProcessor mShortcutRequestPinProcessor;
Makoto Onuki475c3652017-05-08 14:29:03 -0700322 private final ShortcutBitmapSaver mShortcutBitmapSaver;
Makoto Onuki50a320e2017-05-31 14:38:42 -0700323 private final ShortcutDumpFiles mShortcutDumpFiles;
Makoto Onuki2d895c32016-12-02 15:48:40 -0800324
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700325 @GuardedBy("mLock")
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700326 final SparseIntArray mUidState = new SparseIntArray();
327
328 @GuardedBy("mLock")
329 final SparseLongArray mUidLastForegroundElapsedTime = new SparseLongArray();
330
331 @GuardedBy("mLock")
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700332 private List<Integer> mDirtyUserIds = new ArrayList<>();
333
Makoto Onukic51b2872016-05-04 15:24:50 -0700334 private final AtomicBoolean mBootCompleted = new AtomicBoolean();
335
Makoto Onuki905e8852016-03-28 10:40:58 -0700336 private static final int PACKAGE_MATCH_FLAGS =
337 PackageManager.MATCH_DIRECT_BOOT_AWARE
Makoto Onukib08790c2016-06-23 14:05:46 -0700338 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
339 | PackageManager.MATCH_UNINSTALLED_PACKAGES;
Makoto Onuki905e8852016-03-28 10:40:58 -0700340
Makoto Onukie63b04a2017-12-11 14:47:19 -0800341 /**
342 * Note we use a fine-grained lock for {@link #mUnlockedUsers} due to b/64303666.
343 */
344 @GuardedBy("mUnlockedUsers")
Makoto Onuki02f338e2016-07-29 09:40:40 -0700345 final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
346
Makoto Onuki2e210c42016-03-30 08:30:36 -0700347 // Stats
348 @VisibleForTesting
349 interface Stats {
350 int GET_DEFAULT_HOME = 0;
351 int GET_PACKAGE_INFO = 1;
352 int GET_PACKAGE_INFO_WITH_SIG = 2;
353 int GET_APPLICATION_INFO = 3;
354 int LAUNCHER_PERMISSION_CHECK = 4;
Makoto Onuki6c1dbd52016-05-02 15:19:32 -0700355 int CLEANUP_DANGLING_BITMAPS = 5;
Makoto Onukib08790c2016-06-23 14:05:46 -0700356 int GET_ACTIVITY_WITH_METADATA = 6;
Makoto Onuki6dd9fb72016-06-01 13:55:54 -0700357 int GET_INSTALLED_PACKAGES = 7;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700358 int CHECK_PACKAGE_CHANGES = 8;
Makoto Onuki157b1622016-06-02 16:13:10 -0700359 int GET_APPLICATION_RESOURCES = 9;
360 int RESOURCE_NAME_LOOKUP = 10;
Makoto Onukib08790c2016-06-23 14:05:46 -0700361 int GET_LAUNCHER_ACTIVITY = 11;
362 int CHECK_LAUNCHER_ACTIVITY = 12;
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700363 int IS_ACTIVITY_ENABLED = 13;
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700364 int PACKAGE_UPDATE_CHECK = 14;
Makoto Onuki085a05c2016-08-19 11:39:29 -0700365 int ASYNC_PRELOAD_USER_DELAY = 15;
Makoto Onuki2d895c32016-12-02 15:48:40 -0800366 int GET_DEFAULT_LAUNCHER = 16;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700367
Makoto Onuki2d895c32016-12-02 15:48:40 -0800368 int COUNT = GET_DEFAULT_LAUNCHER + 1;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700369 }
370
Makoto Onuki84d59342018-02-02 09:22:38 -0800371 private final StatLogger mStatLogger = new StatLogger(new String[] {
Makoto Onuki085a05c2016-08-19 11:39:29 -0700372 "getHomeActivities()",
373 "Launcher permission check",
374 "getPackageInfo()",
375 "getPackageInfo(SIG)",
376 "getApplicationInfo",
377 "cleanupDanglingBitmaps",
378 "getActivity+metadata",
379 "getInstalledPackages",
380 "checkPackageChanges",
381 "getApplicationResources",
382 "resourceNameLookup",
383 "getLauncherActivity",
384 "checkLauncherActivity",
385 "isActivityEnabled",
386 "packageUpdateCheck",
Makoto Onuki2d895c32016-12-02 15:48:40 -0800387 "asyncPreloadUserDelay",
388 "getDefaultLauncher()"
Makoto Onuki84d59342018-02-02 09:22:38 -0800389 });
Makoto Onuki2e210c42016-03-30 08:30:36 -0700390
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700391 private static final int PROCESS_STATE_FOREGROUND_THRESHOLD =
Dianne Hackborn10fc4fd2017-12-19 17:23:13 -0800392 ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700393
Makoto Onuki7001a612016-05-27 13:24:28 -0700394 static final int OPERATION_SET = 0;
395 static final int OPERATION_ADD = 1;
396 static final int OPERATION_UPDATE = 2;
397
398 /** @hide */
399 @IntDef(value = {
400 OPERATION_SET,
401 OPERATION_ADD,
402 OPERATION_UPDATE
Makoto Onukib08790c2016-06-23 14:05:46 -0700403 })
Makoto Onuki7001a612016-05-27 13:24:28 -0700404 @Retention(RetentionPolicy.SOURCE)
Makoto Onukib08790c2016-06-23 14:05:46 -0700405 @interface ShortcutOperation {
406 }
Makoto Onuki7001a612016-05-27 13:24:28 -0700407
Makoto Onukia2241832016-07-06 13:28:37 -0700408 @GuardedBy("mLock")
409 private int mWtfCount = 0;
410
411 @GuardedBy("mLock")
412 private Exception mLastWtfStacktrace;
413
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700414 static class InvalidFileFormatException extends Exception {
415 public InvalidFileFormatException(String message, Throwable cause) {
416 super(message, cause);
417 }
418 }
419
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800420 public ShortcutService(Context context) {
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700421 this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700422 }
423
424 @VisibleForTesting
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700425 ShortcutService(Context context, Looper looper, boolean onlyForPackageManagerApis) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800426 mContext = Preconditions.checkNotNull(context);
427 LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700428 mHandler = new Handler(looper);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700429 mIPackageManager = AppGlobals.getPackageManager();
Makoto Onukiac042502016-05-20 16:39:42 -0700430 mPackageManagerInternal = Preconditions.checkNotNull(
431 LocalServices.getService(PackageManagerInternal.class));
432 mUserManager = Preconditions.checkNotNull(context.getSystemService(UserManager.class));
433 mUsageStatsManagerInternal = Preconditions.checkNotNull(
434 LocalServices.getService(UsageStatsManagerInternal.class));
Makoto Onuki33525d22016-08-03 15:45:24 -0700435 mActivityManagerInternal = Preconditions.checkNotNull(
436 LocalServices.getService(ActivityManagerInternal.class));
Makoto Onukicdc78f72016-03-21 15:47:52 -0700437
Makoto Onuki2d895c32016-12-02 15:48:40 -0800438 mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock);
Makoto Onuki475c3652017-05-08 14:29:03 -0700439 mShortcutBitmapSaver = new ShortcutBitmapSaver(this);
Makoto Onuki50a320e2017-05-31 14:38:42 -0700440 mShortcutDumpFiles = new ShortcutDumpFiles(this);
Makoto Onuki2d895c32016-12-02 15:48:40 -0800441
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700442 if (onlyForPackageManagerApis) {
443 return; // Don't do anything further. For unit tests only.
444 }
445
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700446 // Register receivers.
447
448 // We need to set a priority, so let's just not use PackageMonitor for now.
449 // TODO Refactor PackageMonitor to support priorities.
450 final IntentFilter packageFilter = new IntentFilter();
451 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
452 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
453 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
454 packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
455 packageFilter.addDataScheme("package");
456 packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
457 mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
458 packageFilter, null, mHandler);
459
Makoto Onuki10305202016-07-14 18:14:08 -0700460 final IntentFilter preferedActivityFilter = new IntentFilter();
461 preferedActivityFilter.addAction(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED);
462 preferedActivityFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
463 mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
464 preferedActivityFilter, null, mHandler);
465
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700466 final IntentFilter localeFilter = new IntentFilter();
467 localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
468 localeFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
469 mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL,
470 localeFilter, null, mHandler);
Makoto Onukif34c3082016-07-13 10:25:25 -0700471
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700472 injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
473 | ActivityManager.UID_OBSERVER_GONE);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800474 }
475
Makoto Onuki84d59342018-02-02 09:22:38 -0800476 long getStatStartTime() {
477 return mStatLogger.getTime();
478 }
479
Makoto Onuki2e210c42016-03-30 08:30:36 -0700480 void logDurationStat(int statId, long start) {
Makoto Onuki84d59342018-02-02 09:22:38 -0800481 mStatLogger.logDurationStat(statId, start);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700482 }
483
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700484 public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
485 // TODO This should get the per-user locale. b/30123329 b/30119489
486 return LocaleList.getDefault().toLanguageTags();
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700487 }
488
489 final private IUidObserver mUidObserver = new IUidObserver.Stub() {
Makoto Onukib08790c2016-06-23 14:05:46 -0700490 @Override
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700491 public void onUidStateChanged(int uid, int procState, long procStateSeq) {
Makoto Onukidc3f6d12017-09-22 17:22:50 -0700492 injectPostToHandler(() -> handleOnUidStateChanged(uid, procState));
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700493 }
494
Makoto Onukib08790c2016-06-23 14:05:46 -0700495 @Override
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700496 public void onUidGone(int uid, boolean disabled) {
Makoto Onukidc3f6d12017-09-22 17:22:50 -0700497 injectPostToHandler(() ->
498 handleOnUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT));
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700499 }
500
Makoto Onukib08790c2016-06-23 14:05:46 -0700501 @Override
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700502 public void onUidActive(int uid) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700503 }
504
Makoto Onukib08790c2016-06-23 14:05:46 -0700505 @Override
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700506 public void onUidIdle(int uid, boolean disabled) {
507 }
508
509 @Override public void onUidCachedChanged(int uid, boolean cached) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700510 }
511 };
512
513 void handleOnUidStateChanged(int uid, int procState) {
514 if (DEBUG_PROCSTATE) {
515 Slog.d(TAG, "onUidStateChanged: uid=" + uid + " state=" + procState);
516 }
517 synchronized (mLock) {
518 mUidState.put(uid, procState);
519
520 // We need to keep track of last time an app comes to foreground.
521 // See ShortcutPackage.getApiCallCount() for how it's used.
522 // It doesn't have to be persisted, but it needs to be the elapsed time.
523 if (isProcessStateForeground(procState)) {
524 mUidLastForegroundElapsedTime.put(uid, injectElapsedRealtime());
525 }
526 }
527 }
528
529 private boolean isProcessStateForeground(int processState) {
Dianne Hackborn5614bf52016-11-07 17:26:41 -0800530 return processState <= PROCESS_STATE_FOREGROUND_THRESHOLD;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700531 }
532
533 boolean isUidForegroundLocked(int uid) {
534 if (uid == Process.SYSTEM_UID) {
535 // IUidObserver doesn't report the state of SYSTEM, but it always has bound services,
536 // so it's foreground anyway.
537 return true;
538 }
Makoto Onuki33525d22016-08-03 15:45:24 -0700539 // First, check with the local cache.
540 if (isProcessStateForeground(mUidState.get(uid, ActivityManager.MAX_PROCESS_STATE))) {
541 return true;
542 }
543 // If the cache says background, reach out to AM. Since it'll internally need to hold
544 // the AM lock, we use it as a last resort.
545 return isProcessStateForeground(mActivityManagerInternal.getUidProcessState(uid));
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700546 }
547
548 long getUidLastForegroundElapsedTimeLocked(int uid) {
549 return mUidLastForegroundElapsedTime.get(uid);
550 }
551
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800552 /**
553 * System service lifecycle.
554 */
555 public static final class Lifecycle extends SystemService {
556 final ShortcutService mService;
557
558 public Lifecycle(Context context) {
559 super(context);
Makoto Onukia4f89b12017-10-05 10:37:55 -0700560 if (DEBUG) {
561 Binder.LOG_RUNTIME_EXCEPTION = true;
562 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800563 mService = new ShortcutService(context);
564 }
565
566 @Override
567 public void onStart() {
568 publishBinderService(Context.SHORTCUT_SERVICE, mService);
569 }
570
571 @Override
572 public void onBootPhase(int phase) {
573 mService.onBootPhase(phase);
574 }
575
576 @Override
Makoto Onuki01ce92b2017-04-28 12:24:16 -0700577 public void onStopUser(int userHandle) {
578 mService.handleStopUser(userHandle);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800579 }
580
581 @Override
Makoto Onukif3a572b2016-03-10 12:28:38 -0800582 public void onUnlockUser(int userId) {
Makoto Onukicdc78f72016-03-21 15:47:52 -0700583 mService.handleUnlockUser(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800584 }
585 }
586
587 /** lifecycle event */
588 void onBootPhase(int phase) {
589 if (DEBUG) {
590 Slog.d(TAG, "onBootPhase: " + phase);
591 }
592 switch (phase) {
593 case SystemService.PHASE_LOCK_SETTINGS_READY:
594 initialize();
595 break;
Makoto Onukic51b2872016-05-04 15:24:50 -0700596 case SystemService.PHASE_BOOT_COMPLETED:
597 mBootCompleted.set(true);
598 break;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800599 }
600 }
601
602 /** lifecycle event */
Makoto Onukicdc78f72016-03-21 15:47:52 -0700603 void handleUnlockUser(int userId) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700604 if (DEBUG) {
Makoto Onuki085a05c2016-08-19 11:39:29 -0700605 Slog.d(TAG, "handleUnlockUser: user=" + userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -0700606 }
Makoto Onukie63b04a2017-12-11 14:47:19 -0800607 synchronized (mUnlockedUsers) {
Makoto Onuki02f338e2016-07-29 09:40:40 -0700608 mUnlockedUsers.put(userId, true);
Makoto Onukicdc78f72016-03-21 15:47:52 -0700609 }
Makoto Onuki085a05c2016-08-19 11:39:29 -0700610
611 // Preload the user data.
612 // Note, we don't use mHandler here but instead just start a new thread.
613 // This is because mHandler (which uses com.android.internal.os.BackgroundThread) is very
614 // busy at this point and this could take hundreds of milliseconds, which would be too
615 // late since the launcher would already have started.
616 // So we just create a new thread. This code runs rarely, so we don't use a thread pool
617 // or anything.
Makoto Onuki84d59342018-02-02 09:22:38 -0800618 final long start = getStatStartTime();
Makoto Onuki085a05c2016-08-19 11:39:29 -0700619 injectRunOnNewThread(() -> {
620 synchronized (mLock) {
621 logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
622 getUserShortcutsLocked(userId);
623 }
624 });
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800625 }
626
627 /** lifecycle event */
Makoto Onuki01ce92b2017-04-28 12:24:16 -0700628 void handleStopUser(int userId) {
Makoto Onuki02f338e2016-07-29 09:40:40 -0700629 if (DEBUG) {
Makoto Onuki01ce92b2017-04-28 12:24:16 -0700630 Slog.d(TAG, "handleStopUser: user=" + userId);
Makoto Onuki02f338e2016-07-29 09:40:40 -0700631 }
Makoto Onukicdc78f72016-03-21 15:47:52 -0700632 synchronized (mLock) {
633 unloadUserLocked(userId);
Makoto Onuki02f338e2016-07-29 09:40:40 -0700634
Makoto Onukie63b04a2017-12-11 14:47:19 -0800635 synchronized (mUnlockedUsers) {
636 mUnlockedUsers.put(userId, false);
637 }
Makoto Onukicdc78f72016-03-21 15:47:52 -0700638 }
639 }
640
641 private void unloadUserLocked(int userId) {
642 if (DEBUG) {
643 Slog.d(TAG, "unloadUserLocked: user=" + userId);
644 }
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700645 // Save all dirty information.
646 saveDirtyInfo();
647
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800648 // Unload
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -0800649 mUsers.delete(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800650 }
651
652 /** Return the base state file name */
653 private AtomicFile getBaseStateFile() {
654 final File path = new File(injectSystemDataPath(), FILENAME_BASE_STATE);
655 path.mkdirs();
656 return new AtomicFile(path);
657 }
658
659 /**
660 * Init the instance. (load the state file, etc)
661 */
662 private void initialize() {
663 synchronized (mLock) {
Makoto Onuki4362a662016-03-08 18:59:09 -0800664 loadConfigurationLocked();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800665 loadBaseStateLocked();
666 }
667 }
668
Makoto Onuki4362a662016-03-08 18:59:09 -0800669 /**
670 * Load the configuration from Settings.
671 */
672 private void loadConfigurationLocked() {
673 updateConfigurationLocked(injectShortcutManagerConstants());
674 }
Makoto Onuki55046222016-03-08 10:49:47 -0800675
Makoto Onuki4362a662016-03-08 18:59:09 -0800676 /**
677 * Load the configuration from Settings.
678 */
679 @VisibleForTesting
680 boolean updateConfigurationLocked(String config) {
681 boolean result = true;
682
683 final KeyValueListParser parser = new KeyValueListParser(',');
684 try {
685 parser.setString(config);
686 } catch (IllegalArgumentException e) {
687 // Failed to parse the settings string, log this and move on
688 // with defaults.
689 Slog.e(TAG, "Bad shortcut manager settings", e);
690 result = false;
691 }
692
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700693 mSaveDelayMillis = Math.max(0, (int) parser.getLong(ConfigConstants.KEY_SAVE_DELAY_MILLIS,
694 DEFAULT_SAVE_DELAY_MS));
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700695
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700696 mResetInterval = Math.max(1, parser.getLong(
Makoto Onuki4362a662016-03-08 18:59:09 -0800697 ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC)
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700698 * 1000L);
Makoto Onuki4362a662016-03-08 18:59:09 -0800699
Makoto Onukib6d35232016-04-04 15:57:17 -0700700 mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong(
701 ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL));
Makoto Onuki4362a662016-03-08 18:59:09 -0800702
Makoto Onukib5a012f2016-06-21 11:13:53 -0700703 mMaxShortcuts = Math.max(0, (int) parser.getLong(
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700704 ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP));
Makoto Onuki4362a662016-03-08 18:59:09 -0800705
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700706 final int iconDimensionDp = Math.max(1, injectIsLowRamDevice()
Makoto Onuki4362a662016-03-08 18:59:09 -0800707 ? (int) parser.getLong(
Makoto Onukib08790c2016-06-23 14:05:46 -0700708 ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM,
709 DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP)
Makoto Onuki4362a662016-03-08 18:59:09 -0800710 : (int) parser.getLong(
Makoto Onukib08790c2016-06-23 14:05:46 -0700711 ConfigConstants.KEY_MAX_ICON_DIMENSION_DP,
712 DEFAULT_MAX_ICON_DIMENSION_DP));
Makoto Onuki4362a662016-03-08 18:59:09 -0800713
714 mMaxIconDimension = injectDipToPixel(iconDimensionDp);
715
716 mIconPersistFormat = CompressFormat.valueOf(
717 parser.getString(ConfigConstants.KEY_ICON_FORMAT, DEFAULT_ICON_PERSIST_FORMAT));
718
719 mIconPersistQuality = (int) parser.getLong(
720 ConfigConstants.KEY_ICON_QUALITY,
721 DEFAULT_ICON_PERSIST_QUALITY);
722
723 return result;
724 }
725
726 @VisibleForTesting
727 String injectShortcutManagerConstants() {
728 return android.provider.Settings.Global.getString(
729 mContext.getContentResolver(),
730 android.provider.Settings.Global.SHORTCUT_MANAGER_CONSTANTS);
731 }
732
733 @VisibleForTesting
734 int injectDipToPixel(int dip) {
735 return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
736 mContext.getResources().getDisplayMetrics());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800737 }
738
Makoto Onuki55046222016-03-08 10:49:47 -0800739 // === Persisting ===
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800740
741 @Nullable
Makoto Onuki41066a62016-03-09 16:18:44 -0800742 static String parseStringAttribute(XmlPullParser parser, String attribute) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800743 return parser.getAttributeValue(null, attribute);
744 }
745
Makoto Onuki0acbb142016-03-22 17:02:57 -0700746 static boolean parseBooleanAttribute(XmlPullParser parser, String attribute) {
747 return parseLongAttribute(parser, attribute) == 1;
748 }
749
Makoto Onukia4f89b12017-10-05 10:37:55 -0700750 static boolean parseBooleanAttribute(XmlPullParser parser, String attribute, boolean def) {
751 return parseLongAttribute(parser, attribute, (def ? 1 : 0)) == 1;
752 }
753
Makoto Onuki41066a62016-03-09 16:18:44 -0800754 static int parseIntAttribute(XmlPullParser parser, String attribute) {
755 return (int) parseLongAttribute(parser, attribute);
756 }
757
Makoto Onukid99c6f02016-03-28 11:02:54 -0700758 static int parseIntAttribute(XmlPullParser parser, String attribute, int def) {
759 return (int) parseLongAttribute(parser, attribute, def);
760 }
761
Makoto Onuki41066a62016-03-09 16:18:44 -0800762 static long parseLongAttribute(XmlPullParser parser, String attribute) {
Makoto Onukid99c6f02016-03-28 11:02:54 -0700763 return parseLongAttribute(parser, attribute, 0);
764 }
765
766 static long parseLongAttribute(XmlPullParser parser, String attribute, long def) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800767 final String value = parseStringAttribute(parser, attribute);
768 if (TextUtils.isEmpty(value)) {
Makoto Onukid99c6f02016-03-28 11:02:54 -0700769 return def;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800770 }
771 try {
772 return Long.parseLong(value);
773 } catch (NumberFormatException e) {
774 Slog.e(TAG, "Error parsing long " + value);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700775 return def;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800776 }
777 }
778
779 @Nullable
Makoto Onuki41066a62016-03-09 16:18:44 -0800780 static ComponentName parseComponentNameAttribute(XmlPullParser parser, String attribute) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800781 final String value = parseStringAttribute(parser, attribute);
782 if (TextUtils.isEmpty(value)) {
783 return null;
784 }
785 return ComponentName.unflattenFromString(value);
786 }
787
788 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700789 static Intent parseIntentAttributeNoDefault(XmlPullParser parser, String attribute) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800790 final String value = parseStringAttribute(parser, attribute);
Makoto Onukib5a012f2016-06-21 11:13:53 -0700791 Intent parsed = null;
792 if (!TextUtils.isEmpty(value)) {
793 try {
794 parsed = Intent.parseUri(value, /* flags =*/ 0);
795 } catch (URISyntaxException e) {
796 Slog.e(TAG, "Error parsing intent", e);
797 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800798 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700799 return parsed;
800 }
801
802 @Nullable
803 static Intent parseIntentAttribute(XmlPullParser parser, String attribute) {
804 Intent parsed = parseIntentAttributeNoDefault(parser, attribute);
Makoto Onukib5a012f2016-06-21 11:13:53 -0700805 if (parsed == null) {
806 // Default intent.
807 parsed = new Intent(Intent.ACTION_VIEW);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800808 }
Makoto Onukib5a012f2016-06-21 11:13:53 -0700809 return parsed;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800810 }
811
Makoto Onuki41066a62016-03-09 16:18:44 -0800812 static void writeTagValue(XmlSerializer out, String tag, String value) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800813 if (TextUtils.isEmpty(value)) return;
814
815 out.startTag(null, tag);
816 out.attribute(null, ATTR_VALUE, value);
817 out.endTag(null, tag);
818 }
819
Makoto Onuki41066a62016-03-09 16:18:44 -0800820 static void writeTagValue(XmlSerializer out, String tag, long value) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800821 writeTagValue(out, tag, Long.toString(value));
822 }
823
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800824 static void writeTagValue(XmlSerializer out, String tag, ComponentName name) throws IOException {
825 if (name == null) return;
826 writeTagValue(out, tag, name.flattenToString());
827 }
828
Makoto Onuki41066a62016-03-09 16:18:44 -0800829 static void writeTagExtra(XmlSerializer out, String tag, PersistableBundle bundle)
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800830 throws IOException, XmlPullParserException {
831 if (bundle == null) return;
832
833 out.startTag(null, tag);
834 bundle.saveToXml(out);
835 out.endTag(null, tag);
836 }
837
Makoto Onuki22fcc682016-05-17 14:52:19 -0700838 static void writeAttr(XmlSerializer out, String name, CharSequence value) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800839 if (TextUtils.isEmpty(value)) return;
840
Makoto Onuki22fcc682016-05-17 14:52:19 -0700841 out.attribute(null, name, value.toString());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800842 }
843
Makoto Onuki41066a62016-03-09 16:18:44 -0800844 static void writeAttr(XmlSerializer out, String name, long value) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800845 writeAttr(out, name, String.valueOf(value));
846 }
847
Makoto Onuki0acbb142016-03-22 17:02:57 -0700848 static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException {
849 if (value) {
850 writeAttr(out, name, "1");
Makoto Onukia4f89b12017-10-05 10:37:55 -0700851 } else {
852 writeAttr(out, name, "0");
Makoto Onuki0acbb142016-03-22 17:02:57 -0700853 }
854 }
855
Makoto Onuki41066a62016-03-09 16:18:44 -0800856 static void writeAttr(XmlSerializer out, String name, ComponentName comp) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800857 if (comp == null) return;
858 writeAttr(out, name, comp.flattenToString());
859 }
860
Makoto Onuki41066a62016-03-09 16:18:44 -0800861 static void writeAttr(XmlSerializer out, String name, Intent intent) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800862 if (intent == null) return;
863
864 writeAttr(out, name, intent.toUri(/* flags =*/ 0));
865 }
866
867 @VisibleForTesting
868 void saveBaseStateLocked() {
869 final AtomicFile file = getBaseStateFile();
870 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700871 Slog.d(TAG, "Saving to " + file.getBaseFile());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800872 }
873
874 FileOutputStream outs = null;
875 try {
876 outs = file.startWrite();
877
878 // Write to XML
879 XmlSerializer out = new FastXmlSerializer();
880 out.setOutput(outs, StandardCharsets.UTF_8.name());
881 out.startDocument(null, true);
882 out.startTag(null, TAG_ROOT);
883
884 // Body.
885 writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime);
886
887 // Epilogue.
888 out.endTag(null, TAG_ROOT);
889 out.endDocument();
890
891 // Close.
892 file.finishWrite(outs);
893 } catch (IOException e) {
894 Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
895 file.failWrite(outs);
896 }
897 }
898
899 private void loadBaseStateLocked() {
900 mRawLastResetTime = 0;
901
902 final AtomicFile file = getBaseStateFile();
903 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700904 Slog.d(TAG, "Loading from " + file.getBaseFile());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800905 }
906 try (FileInputStream in = file.openRead()) {
907 XmlPullParser parser = Xml.newPullParser();
908 parser.setInput(in, StandardCharsets.UTF_8.name());
909
910 int type;
911 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
912 if (type != XmlPullParser.START_TAG) {
913 continue;
914 }
915 final int depth = parser.getDepth();
916 // Check the root tag
917 final String tag = parser.getName();
918 if (depth == 1) {
919 if (!TAG_ROOT.equals(tag)) {
920 Slog.e(TAG, "Invalid root tag: " + tag);
921 return;
922 }
923 continue;
924 }
925 // Assume depth == 2
926 switch (tag) {
927 case TAG_LAST_RESET_TIME:
928 mRawLastResetTime = parseLongAttribute(parser, ATTR_VALUE);
929 break;
930 default:
931 Slog.e(TAG, "Invalid tag: " + tag);
932 break;
933 }
934 }
935 } catch (FileNotFoundException e) {
936 // Use the default
Makoto Onukib08790c2016-06-23 14:05:46 -0700937 } catch (IOException | XmlPullParserException e) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800938 Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
939
940 mRawLastResetTime = 0;
941 }
942 // Adjust the last reset time.
943 getLastResetTimeLocked();
944 }
945
Makoto Onuki0eed4412016-07-21 11:21:59 -0700946 @VisibleForTesting
947 final File getUserFile(@UserIdInt int userId) {
948 return new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
949 }
950
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800951 private void saveUserLocked(@UserIdInt int userId) {
Makoto Onuki0eed4412016-07-21 11:21:59 -0700952 final File path = getUserFile(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800953 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700954 Slog.d(TAG, "Saving to " + path);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800955 }
Makoto Onuki475c3652017-05-08 14:29:03 -0700956
957 mShortcutBitmapSaver.waitForAllSavesLocked();
958
Makoto Onuki0eed4412016-07-21 11:21:59 -0700959 path.getParentFile().mkdirs();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800960 final AtomicFile file = new AtomicFile(path);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700961 FileOutputStream os = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800962 try {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700963 os = file.startWrite();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800964
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700965 saveUserInternalLocked(userId, os, /* forBackup= */ false);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800966
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700967 file.finishWrite(os);
Makoto Onuki1e173232016-08-10 10:47:13 -0700968
969 // Remove all dangling bitmap files.
970 cleanupDanglingBitmapDirectoriesLocked(userId);
Makoto Onukib08790c2016-06-23 14:05:46 -0700971 } catch (XmlPullParserException | IOException e) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800972 Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700973 file.failWrite(os);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800974 }
975 }
976
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700977 private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
978 boolean forBackup) throws IOException, XmlPullParserException {
979
980 final BufferedOutputStream bos = new BufferedOutputStream(os);
981
982 // Write to XML
983 XmlSerializer out = new FastXmlSerializer();
984 out.setOutput(bos, StandardCharsets.UTF_8.name());
985 out.startDocument(null, true);
986
Makoto Onukic51b2872016-05-04 15:24:50 -0700987 getUserShortcutsLocked(userId).saveToXml(out, forBackup);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700988
989 out.endDocument();
990
991 bos.flush();
992 os.flush();
993 }
994
Makoto Onuki41066a62016-03-09 16:18:44 -0800995 static IOException throwForInvalidTag(int depth, String tag) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800996 throw new IOException(String.format("Invalid tag '%s' found at depth %d", tag, depth));
997 }
998
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700999 static void warnForInvalidTag(int depth, String tag) throws IOException {
1000 Slog.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth));
1001 }
1002
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001003 @Nullable
Makoto Onuki31459242016-03-22 11:12:18 -07001004 private ShortcutUser loadUserLocked(@UserIdInt int userId) {
Makoto Onuki0eed4412016-07-21 11:21:59 -07001005 final File path = getUserFile(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001006 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001007 Slog.d(TAG, "Loading from " + path);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001008 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001009 final AtomicFile file = new AtomicFile(path);
1010
1011 final FileInputStream in;
1012 try {
1013 in = file.openRead();
1014 } catch (FileNotFoundException e) {
1015 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001016 Slog.d(TAG, "Not found " + path);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001017 }
1018 return null;
1019 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001020 try {
Makoto Onukib08790c2016-06-23 14:05:46 -07001021 final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false);
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001022 return ret;
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07001023 } catch (IOException | XmlPullParserException | InvalidFileFormatException e) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001024 Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
1025 return null;
1026 } finally {
1027 IoUtils.closeQuietly(in);
1028 }
1029 }
1030
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001031 private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07001032 boolean fromBackup) throws XmlPullParserException, IOException,
1033 InvalidFileFormatException {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001034
1035 final BufferedInputStream bis = new BufferedInputStream(is);
1036
1037 ShortcutUser ret = null;
1038 XmlPullParser parser = Xml.newPullParser();
1039 parser.setInput(bis, StandardCharsets.UTF_8.name());
1040
1041 int type;
1042 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
1043 if (type != XmlPullParser.START_TAG) {
1044 continue;
1045 }
1046 final int depth = parser.getDepth();
1047
1048 final String tag = parser.getName();
1049 if (DEBUG_LOAD) {
1050 Slog.d(TAG, String.format("depth=%d type=%d name=%s",
1051 depth, type, tag));
1052 }
1053 if ((depth == 1) && ShortcutUser.TAG_ROOT.equals(tag)) {
1054 ret = ShortcutUser.loadFromXml(this, parser, userId, fromBackup);
1055 continue;
1056 }
1057 throwForInvalidTag(depth, tag);
1058 }
1059 return ret;
1060 }
1061
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001062 private void scheduleSaveBaseState() {
Makoto Onuki0acbb142016-03-22 17:02:57 -07001063 scheduleSaveInner(UserHandle.USER_NULL); // Special case -- use USER_NULL for base state.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001064 }
1065
Makoto Onuki2d5b4652016-03-11 16:09:54 -08001066 void scheduleSaveUser(@UserIdInt int userId) {
Makoto Onuki0acbb142016-03-22 17:02:57 -07001067 scheduleSaveInner(userId);
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001068 }
1069
1070 // In order to re-schedule, we need to reuse the same instance, so keep it in final.
1071 private final Runnable mSaveDirtyInfoRunner = this::saveDirtyInfo;
1072
Makoto Onuki0acbb142016-03-22 17:02:57 -07001073 private void scheduleSaveInner(@UserIdInt int userId) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001074 if (DEBUG) {
1075 Slog.d(TAG, "Scheduling to save for " + userId);
1076 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001077 synchronized (mLock) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001078 if (!mDirtyUserIds.contains(userId)) {
1079 mDirtyUserIds.add(userId);
1080 }
1081 }
1082 // If already scheduled, remove that and re-schedule in N seconds.
1083 mHandler.removeCallbacks(mSaveDirtyInfoRunner);
1084 mHandler.postDelayed(mSaveDirtyInfoRunner, mSaveDelayMillis);
1085 }
1086
1087 @VisibleForTesting
1088 void saveDirtyInfo() {
1089 if (DEBUG) {
1090 Slog.d(TAG, "saveDirtyInfo");
1091 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07001092 try {
1093 synchronized (mLock) {
1094 for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
1095 final int userId = mDirtyUserIds.get(i);
1096 if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
1097 saveBaseStateLocked();
1098 } else {
1099 saveUserLocked(userId);
1100 }
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001101 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07001102 mDirtyUserIds.clear();
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001103 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07001104 } catch (Exception e) {
1105 wtf("Exception in saveDirtyInfo", e);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001106 }
1107 }
1108
1109 /** Return the last reset time. */
1110 long getLastResetTimeLocked() {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001111 updateTimesLocked();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001112 return mRawLastResetTime;
1113 }
1114
1115 /** Return the next reset time. */
1116 long getNextResetTimeLocked() {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001117 updateTimesLocked();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001118 return mRawLastResetTime + mResetInterval;
1119 }
1120
Makoto Onuki4554d0e2016-03-14 15:51:41 -07001121 static boolean isClockValid(long time) {
1122 return time >= 1420070400; // Thu, 01 Jan 2015 00:00:00 GMT
1123 }
1124
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001125 /**
1126 * Update the last reset time.
1127 */
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001128 private void updateTimesLocked() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001129
1130 final long now = injectCurrentTimeMillis();
1131
1132 final long prevLastResetTime = mRawLastResetTime;
1133
1134 if (mRawLastResetTime == 0) { // first launch.
1135 // TODO Randomize??
1136 mRawLastResetTime = now;
1137 } else if (now < mRawLastResetTime) {
1138 // Clock rewound.
Makoto Onuki4554d0e2016-03-14 15:51:41 -07001139 if (isClockValid(now)) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001140 Slog.w(TAG, "Clock rewound");
Makoto Onuki4554d0e2016-03-14 15:51:41 -07001141 // TODO Randomize??
1142 mRawLastResetTime = now;
1143 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001144 } else {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001145 if ((mRawLastResetTime + mResetInterval) <= now) {
1146 final long offset = mRawLastResetTime % mResetInterval;
1147 mRawLastResetTime = ((now / mResetInterval) * mResetInterval) + offset;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001148 }
1149 }
1150 if (prevLastResetTime != mRawLastResetTime) {
1151 scheduleSaveBaseState();
1152 }
1153 }
1154
Makoto Onuki1e173232016-08-10 10:47:13 -07001155 // Requires mLock held, but "Locked" prefix would look weired so we just say "L".
Makoto Onuki02f338e2016-07-29 09:40:40 -07001156 protected boolean isUserUnlockedL(@UserIdInt int userId) {
Makoto Onuki1e173232016-08-10 10:47:13 -07001157 // First, check the local copy.
Makoto Onukie63b04a2017-12-11 14:47:19 -08001158 synchronized (mUnlockedUsers) {
1159 if (mUnlockedUsers.get(userId)) {
1160 return true;
1161 }
Makoto Onuki1e173232016-08-10 10:47:13 -07001162 }
Makoto Onukie63b04a2017-12-11 14:47:19 -08001163
Makoto Onuki1e173232016-08-10 10:47:13 -07001164 // If the local copy says the user is locked, check with AM for the actual state, since
1165 // the user might just have been unlocked.
1166 // Note we just don't use isUserUnlockingOrUnlocked() here, because it'll return false
1167 // when the user is STOPPING, which we still want to consider as "unlocked".
1168 final long token = injectClearCallingIdentity();
1169 try {
1170 return mUserManager.isUserUnlockingOrUnlocked(userId);
1171 } finally {
1172 injectRestoreCallingIdentity(token);
1173 }
Makoto Onuki9c850012016-07-26 15:50:50 -07001174 }
1175
Makoto Onuki02f338e2016-07-29 09:40:40 -07001176 // Requires mLock held, but "Locked" prefix would look weired so we jsut say "L".
1177 void throwIfUserLockedL(@UserIdInt int userId) {
1178 if (!isUserUnlockedL(userId)) {
Makoto Onuki9c850012016-07-26 15:50:50 -07001179 throw new IllegalStateException("User " + userId + " is locked or not running");
1180 }
1181 }
1182
Makoto Onukicdc78f72016-03-21 15:47:52 -07001183 @GuardedBy("mLock")
1184 @NonNull
Makoto Onuki2e210c42016-03-30 08:30:36 -07001185 private boolean isUserLoadedLocked(@UserIdInt int userId) {
Makoto Onukicdc78f72016-03-21 15:47:52 -07001186 return mUsers.get(userId) != null;
1187 }
1188
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001189 /** Return the per-user state. */
1190 @GuardedBy("mLock")
1191 @NonNull
Makoto Onuki31459242016-03-22 11:12:18 -07001192 ShortcutUser getUserShortcutsLocked(@UserIdInt int userId) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001193 if (!isUserUnlockedL(userId)) {
Makoto Onuki9c850012016-07-26 15:50:50 -07001194 wtf("User still locked");
Makoto Onuki9c850012016-07-26 15:50:50 -07001195 }
1196
Makoto Onuki31459242016-03-22 11:12:18 -07001197 ShortcutUser userPackages = mUsers.get(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001198 if (userPackages == null) {
1199 userPackages = loadUserLocked(userId);
1200 if (userPackages == null) {
Makoto Onukic51b2872016-05-04 15:24:50 -07001201 userPackages = new ShortcutUser(this, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001202 }
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -08001203 mUsers.put(userId, userPackages);
Makoto Onuki085a05c2016-08-19 11:39:29 -07001204
1205 // Also when a user's data is first accessed, scan all packages.
1206 checkPackageChanges(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001207 }
1208 return userPackages;
1209 }
1210
Makoto Onuki708703b2017-12-11 16:38:11 -08001211 /** Return the non-persistent per-user state. */
1212 @GuardedBy("mLock")
1213 @NonNull
1214 ShortcutNonPersistentUser getNonPersistentUserLocked(@UserIdInt int userId) {
1215 ShortcutNonPersistentUser ret = mShortcutNonPersistentUsers.get(userId);
1216 if (ret == null) {
1217 ret = new ShortcutNonPersistentUser(this, userId);
1218 mShortcutNonPersistentUsers.put(userId, ret);
1219 }
1220 return ret;
1221 }
1222
Makoto Onuki2e210c42016-03-30 08:30:36 -07001223 void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
1224 for (int i = mUsers.size() - 1; i >= 0; i--) {
1225 c.accept(mUsers.valueAt(i));
1226 }
1227 }
1228
Makoto Onukic8c33292016-09-12 16:36:59 -07001229 /**
1230 * Return the per-user per-package state. If the caller is a publisher, use
1231 * {@link #getPackageShortcutsForPublisherLocked} instead.
1232 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001233 @GuardedBy("mLock")
1234 @NonNull
Makoto Onuki31459242016-03-22 11:12:18 -07001235 ShortcutPackage getPackageShortcutsLocked(
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001236 @NonNull String packageName, @UserIdInt int userId) {
Makoto Onukic51b2872016-05-04 15:24:50 -07001237 return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
Makoto Onukide667372016-03-15 14:29:20 -07001238 }
1239
Makoto Onukic8c33292016-09-12 16:36:59 -07001240 /** Return the per-user per-package state. Use this when the caller is a publisher. */
1241 @GuardedBy("mLock")
1242 @NonNull
1243 ShortcutPackage getPackageShortcutsForPublisherLocked(
1244 @NonNull String packageName, @UserIdInt int userId) {
1245 final ShortcutPackage ret = getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
1246 ret.getUser().onCalledByPublisher(packageName);
1247 return ret;
1248 }
1249
Makoto Onukide667372016-03-15 14:29:20 -07001250 @GuardedBy("mLock")
1251 @NonNull
Makoto Onuki2e210c42016-03-30 08:30:36 -07001252 ShortcutLauncher getLauncherShortcutsLocked(
1253 @NonNull String packageName, @UserIdInt int ownerUserId,
1254 @UserIdInt int launcherUserId) {
1255 return getUserShortcutsLocked(ownerUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07001256 .getLauncherShortcuts(packageName, launcherUserId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001257 }
1258
1259 // === Caller validation ===
1260
Makoto Onuki475c3652017-05-08 14:29:03 -07001261 void removeIconLocked(ShortcutInfo shortcut) {
1262 mShortcutBitmapSaver.removeIcon(shortcut);
Makoto Onuki55046222016-03-08 10:49:47 -08001263 }
1264
Makoto Onuki0033b2a2016-04-14 17:19:16 -07001265 public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) {
1266 final File packagePath = new File(getUserBitmapFilePath(userId), packageName);
1267 if (!packagePath.isDirectory()) {
1268 return;
1269 }
1270 if (!(FileUtils.deleteContents(packagePath) && packagePath.delete())) {
1271 Slog.w(TAG, "Unable to remove directory " + packagePath);
1272 }
1273 }
1274
Makoto Onuki475c3652017-05-08 14:29:03 -07001275 /**
1276 * Remove dangling bitmap files for a user.
1277 *
1278 * Note this method must be called with the lock held after calling
1279 * {@link ShortcutBitmapSaver#waitForAllSavesLocked()} to make sure there's no pending bitmap
1280 * saves are going on.
1281 */
Makoto Onuki1e173232016-08-10 10:47:13 -07001282 private void cleanupDanglingBitmapDirectoriesLocked(@UserIdInt int userId) {
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001283 if (DEBUG) {
1284 Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId);
1285 }
Makoto Onuki84d59342018-02-02 09:22:38 -08001286 final long start = getStatStartTime();
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001287
Makoto Onuki1e173232016-08-10 10:47:13 -07001288 final ShortcutUser user = getUserShortcutsLocked(userId);
1289
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001290 final File bitmapDir = getUserBitmapFilePath(userId);
1291 final File[] children = bitmapDir.listFiles();
1292 if (children == null) {
1293 return;
1294 }
1295 for (File child : children) {
1296 if (!child.isDirectory()) {
1297 continue;
1298 }
1299 final String packageName = child.getName();
1300 if (DEBUG) {
1301 Slog.d(TAG, "cleanupDanglingBitmaps: Found directory=" + packageName);
1302 }
1303 if (!user.hasPackage(packageName)) {
1304 if (DEBUG) {
1305 Slog.d(TAG, "Removing dangling bitmap directory: " + packageName);
1306 }
1307 cleanupBitmapsForPackage(userId, packageName);
1308 } else {
1309 cleanupDanglingBitmapFilesLocked(userId, user, packageName, child);
1310 }
1311 }
1312 logDurationStat(Stats.CLEANUP_DANGLING_BITMAPS, start);
1313 }
1314
Makoto Onuki475c3652017-05-08 14:29:03 -07001315 /**
1316 * Remove dangling bitmap files for a package.
1317 *
1318 * Note this method must be called with the lock held after calling
1319 * {@link ShortcutBitmapSaver#waitForAllSavesLocked()} to make sure there's no pending bitmap
1320 * saves are going on.
1321 */
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001322 private void cleanupDanglingBitmapFilesLocked(@UserIdInt int userId, @NonNull ShortcutUser user,
1323 @NonNull String packageName, @NonNull File path) {
1324 final ArraySet<String> usedFiles =
Makoto Onukic51b2872016-05-04 15:24:50 -07001325 user.getPackageShortcuts(packageName).getUsedBitmapFiles();
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001326
1327 for (File child : path.listFiles()) {
1328 if (!child.isFile()) {
1329 continue;
1330 }
1331 final String name = child.getName();
1332 if (!usedFiles.contains(name)) {
1333 if (DEBUG) {
1334 Slog.d(TAG, "Removing dangling bitmap file: " + child.getAbsolutePath());
1335 }
1336 child.delete();
1337 }
1338 }
1339 }
1340
Makoto Onuki55046222016-03-08 10:49:47 -08001341 @VisibleForTesting
1342 static class FileOutputStreamWithPath extends FileOutputStream {
1343 private final File mFile;
1344
1345 public FileOutputStreamWithPath(File file) throws FileNotFoundException {
1346 super(file);
1347 mFile = file;
1348 }
1349
1350 public File getFile() {
1351 return mFile;
1352 }
1353 }
1354
1355 /**
1356 * Build the cached bitmap filename for a shortcut icon.
1357 *
1358 * The filename will be based on the ID, except certain characters will be escaped.
1359 */
Makoto Onuki55046222016-03-08 10:49:47 -08001360 FileOutputStreamWithPath openIconFileForWrite(@UserIdInt int userId, ShortcutInfo shortcut)
1361 throws IOException {
1362 final File packagePath = new File(getUserBitmapFilePath(userId),
Makoto Onuki22fcc682016-05-17 14:52:19 -07001363 shortcut.getPackage());
Makoto Onuki55046222016-03-08 10:49:47 -08001364 if (!packagePath.isDirectory()) {
1365 packagePath.mkdirs();
1366 if (!packagePath.isDirectory()) {
1367 throw new IOException("Unable to create directory " + packagePath);
1368 }
1369 SELinux.restorecon(packagePath);
1370 }
1371
1372 final String baseName = String.valueOf(injectCurrentTimeMillis());
Makoto Onukib08790c2016-06-23 14:05:46 -07001373 for (int suffix = 0; ; suffix++) {
Makoto Onuki55046222016-03-08 10:49:47 -08001374 final String filename = (suffix == 0 ? baseName : baseName + "_" + suffix) + ".png";
1375 final File file = new File(packagePath, filename);
1376 if (!file.exists()) {
1377 if (DEBUG) {
1378 Slog.d(TAG, "Saving icon to " + file.getAbsolutePath());
1379 }
1380 return new FileOutputStreamWithPath(file);
1381 }
1382 }
1383 }
1384
Makoto Onuki475c3652017-05-08 14:29:03 -07001385 void saveIconAndFixUpShortcutLocked(ShortcutInfo shortcut) {
Makoto Onuki55046222016-03-08 10:49:47 -08001386 if (shortcut.hasIconFile() || shortcut.hasIconResource()) {
1387 return;
1388 }
1389
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001390 final long token = injectClearCallingIdentity();
Makoto Onuki55046222016-03-08 10:49:47 -08001391 try {
1392 // Clear icon info on the shortcut.
Makoto Onuki475c3652017-05-08 14:29:03 -07001393 removeIconLocked(shortcut);
Makoto Onuki55046222016-03-08 10:49:47 -08001394
1395 final Icon icon = shortcut.getIcon();
1396 if (icon == null) {
1397 return; // has no icon
1398 }
Hyunyoung Song47037462017-05-08 16:51:43 -07001399 int maxIconDimension = mMaxIconDimension;
Makoto Onukiabe84422016-04-07 09:41:19 -07001400 Bitmap bitmap;
Makoto Onuki55046222016-03-08 10:49:47 -08001401 try {
1402 switch (icon.getType()) {
1403 case Icon.TYPE_RESOURCE: {
1404 injectValidateIconResPackage(shortcut, icon);
1405
1406 shortcut.setIconResourceId(icon.getResId());
1407 shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES);
1408 return;
1409 }
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001410 case Icon.TYPE_BITMAP:
Makoto Onukiabe84422016-04-07 09:41:19 -07001411 bitmap = icon.getBitmap(); // Don't recycle in this case.
Makoto Onuki55046222016-03-08 10:49:47 -08001412 break;
Hyunyoung Song47037462017-05-08 16:51:43 -07001413 case Icon.TYPE_ADAPTIVE_BITMAP: {
1414 bitmap = icon.getBitmap(); // Don't recycle in this case.
1415 maxIconDimension *= (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
Hyunyoung Song8947f592017-05-15 10:12:11 -07001416 break;
Makoto Onuki55046222016-03-08 10:49:47 -08001417 }
Makoto Onuki55046222016-03-08 10:49:47 -08001418 default:
1419 // This shouldn't happen because we've already validated the icon, but
1420 // just in case.
1421 throw ShortcutInfo.getInvalidIconException();
1422 }
Makoto Onuki475c3652017-05-08 14:29:03 -07001423 mShortcutBitmapSaver.saveBitmapLocked(shortcut,
Hyunyoung Song47037462017-05-08 16:51:43 -07001424 maxIconDimension, mIconPersistFormat, mIconPersistQuality);
Makoto Onuki55046222016-03-08 10:49:47 -08001425 } finally {
Makoto Onuki55046222016-03-08 10:49:47 -08001426 // Once saved, we won't use the original icon information, so null it out.
1427 shortcut.clearIcon();
1428 }
1429 } finally {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001430 injectRestoreCallingIdentity(token);
Makoto Onuki55046222016-03-08 10:49:47 -08001431 }
1432 }
1433
1434 // Unfortunately we can't do this check in unit tests because we fake creator package names,
1435 // so override in unit tests.
1436 // TODO CTS this case.
1437 void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07001438 if (!shortcut.getPackage().equals(icon.getResPackage())) {
Makoto Onuki55046222016-03-08 10:49:47 -08001439 throw new IllegalArgumentException(
1440 "Icon resource must reside in shortcut owner package");
1441 }
1442 }
1443
Makoto Onuki55046222016-03-08 10:49:47 -08001444 static Bitmap shrinkBitmap(Bitmap in, int maxSize) {
1445 // Original width/height.
1446 final int ow = in.getWidth();
1447 final int oh = in.getHeight();
1448 if ((ow <= maxSize) && (oh <= maxSize)) {
1449 if (DEBUG) {
1450 Slog.d(TAG, String.format("Icon size %dx%d, no need to shrink", ow, oh));
1451 }
1452 return in;
1453 }
1454 final int longerDimension = Math.max(ow, oh);
1455
1456 // New width and height.
1457 final int nw = ow * maxSize / longerDimension;
1458 final int nh = oh * maxSize / longerDimension;
1459 if (DEBUG) {
1460 Slog.d(TAG, String.format("Icon size %dx%d, shrinking to %dx%d",
1461 ow, oh, nw, nh));
1462 }
1463
1464 final Bitmap scaledBitmap = Bitmap.createBitmap(nw, nh, Bitmap.Config.ARGB_8888);
1465 final Canvas c = new Canvas(scaledBitmap);
1466
1467 final RectF dst = new RectF(0, 0, nw, nh);
1468
1469 c.drawBitmap(in, /*src=*/ null, dst, /* paint =*/ null);
1470
Makoto Onuki55046222016-03-08 10:49:47 -08001471 return scaledBitmap;
1472 }
1473
Makoto Onuki157b1622016-06-02 16:13:10 -07001474 /**
1475 * For a shortcut, update all resource names from resource IDs, and also update all
1476 * resource-based strings.
1477 */
1478 void fixUpShortcutResourceNamesAndValues(ShortcutInfo si) {
1479 final Resources publisherRes = injectGetResourcesForApplicationAsUser(
1480 si.getPackage(), si.getUserId());
1481 if (publisherRes != null) {
Makoto Onuki84d59342018-02-02 09:22:38 -08001482 final long start = getStatStartTime();
Makoto Onuki157b1622016-06-02 16:13:10 -07001483 try {
1484 si.lookupAndFillInResourceNames(publisherRes);
1485 } finally {
1486 logDurationStat(Stats.RESOURCE_NAME_LOOKUP, start);
1487 }
1488 si.resolveResourceStrings(publisherRes);
1489 }
1490 }
1491
Makoto Onuki55046222016-03-08 10:49:47 -08001492 // === Caller validation ===
1493
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001494 private boolean isCallerSystem() {
1495 final int callingUid = injectBinderCallingUid();
Makoto Onukib08790c2016-06-23 14:05:46 -07001496 return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001497 }
1498
1499 private boolean isCallerShell() {
1500 final int callingUid = injectBinderCallingUid();
1501 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
1502 }
1503
1504 private void enforceSystemOrShell() {
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07001505 if (!(isCallerSystem() || isCallerShell())) {
1506 throw new SecurityException("Caller must be system or shell");
1507 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001508 }
1509
1510 private void enforceShell() {
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07001511 if (!isCallerShell()) {
1512 throw new SecurityException("Caller must be shell");
1513 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001514 }
1515
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001516 private void enforceSystem() {
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07001517 if (!isCallerSystem()) {
1518 throw new SecurityException("Caller must be system");
1519 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001520 }
1521
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001522 private void enforceResetThrottlingPermission() {
1523 if (isCallerSystem()) {
1524 return;
1525 }
Makoto Onuki76269922016-07-15 14:58:54 -07001526 enforceCallingOrSelfPermission(
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001527 android.Manifest.permission.RESET_SHORTCUT_MANAGER_THROTTLING, null);
1528 }
1529
Makoto Onuki76269922016-07-15 14:58:54 -07001530 private void enforceCallingOrSelfPermission(
1531 @NonNull String permission, @Nullable String message) {
1532 if (isCallerSystem()) {
1533 return;
1534 }
1535 injectEnforceCallingPermission(permission, message);
1536 }
1537
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001538 /**
1539 * Somehow overriding ServiceContext.enforceCallingPermission() in the unit tests would confuse
1540 * mockito. So instead we extracted it here and override it in the tests.
1541 */
1542 @VisibleForTesting
1543 void injectEnforceCallingPermission(
1544 @NonNull String permission, @Nullable String message) {
1545 mContext.enforceCallingPermission(permission, message);
1546 }
1547
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001548 private void verifyCaller(@NonNull String packageName, @UserIdInt int userId) {
1549 Preconditions.checkStringNotEmpty(packageName, "packageName");
1550
1551 if (isCallerSystem()) {
1552 return; // no check
1553 }
1554
1555 final int callingUid = injectBinderCallingUid();
1556
1557 // Otherwise, make sure the arguments are valid.
1558 if (UserHandle.getUserId(callingUid) != userId) {
1559 throw new SecurityException("Invalid user-ID");
1560 }
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08001561 if (injectGetPackageUid(packageName, userId) != callingUid) {
1562 throw new SecurityException("Calling package name mismatch");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001563 }
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08001564 Preconditions.checkState(!isEphemeralApp(packageName, userId),
1565 "Ephemeral apps can't use ShortcutManager");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001566 }
1567
Makoto Onuki157b1622016-06-02 16:13:10 -07001568 // Overridden in unit tests to execute r synchronously.
1569 void injectPostToHandler(Runnable r) {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001570 mHandler.post(r);
1571 }
1572
Makoto Onuki085a05c2016-08-19 11:39:29 -07001573 void injectRunOnNewThread(Runnable r) {
1574 new Thread(r).start();
1575 }
1576
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001577 /**
Makoto Onuki7001a612016-05-27 13:24:28 -07001578 * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
Makoto Onukib08790c2016-06-23 14:05:46 -07001579 * {@link #getMaxActivityShortcuts()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001580 */
Makoto Onuki7001a612016-05-27 13:24:28 -07001581 void enforceMaxActivityShortcuts(int numShortcuts) {
Makoto Onukib5a012f2016-06-21 11:13:53 -07001582 if (numShortcuts > mMaxShortcuts) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001583 throw new IllegalArgumentException("Max number of dynamic shortcuts exceeded");
1584 }
1585 }
1586
1587 /**
Makoto Onuki7001a612016-05-27 13:24:28 -07001588 * Return the max number of dynamic + manifest shortcuts for each launcher icon.
1589 */
1590 int getMaxActivityShortcuts() {
Makoto Onukib5a012f2016-06-21 11:13:53 -07001591 return mMaxShortcuts;
Makoto Onuki7001a612016-05-27 13:24:28 -07001592 }
1593
1594 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001595 * - Sends a notification to LauncherApps
1596 * - Write to file
1597 */
Makoto Onuki39686e82016-04-13 18:03:00 -07001598 void packageShortcutsChanged(@NonNull String packageName, @UserIdInt int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001599 notifyListeners(packageName, userId);
1600 scheduleSaveUser(userId);
1601 }
1602
1603 private void notifyListeners(@NonNull String packageName, @UserIdInt int userId) {
Makoto Onuki82fb2eb2017-03-31 16:58:26 -07001604 if (DEBUG) {
1605 Slog.d(TAG, String.format(
1606 "Shortcut changes: package=%s, user=%d", packageName, userId));
1607 }
Makoto Onuki157b1622016-06-02 16:13:10 -07001608 injectPostToHandler(() -> {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001609 try {
1610 final ArrayList<ShortcutChangeListener> copy;
1611 synchronized (mLock) {
1612 if (!isUserUnlockedL(userId)) {
1613 return;
1614 }
1615
1616 copy = new ArrayList<>(mListeners);
1617 }
1618 // Note onShortcutChanged() needs to be called with the system service permissions.
1619 for (int i = copy.size() - 1; i >= 0; i--) {
1620 copy.get(i).onShortcutChanged(packageName, userId);
1621 }
1622 } catch (Exception ignore) {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001623 }
1624 });
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001625 }
1626
1627 /**
1628 * Clean up / validate an incoming shortcut.
1629 * - Make sure all mandatory fields are set.
1630 * - Make sure the intent's extras are persistable, and them to set
Makoto Onuki0eed4412016-07-21 11:21:59 -07001631 * {@link ShortcutInfo#mIntentPersistableExtrases}. Also clear its extras.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001632 * - Clear flags.
1633 */
Makoto Onuki2d895c32016-12-02 15:48:40 -08001634 private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate,
1635 boolean forPinRequest) {
Makoto Onukibf563b62017-05-04 10:25:30 -07001636 if (shortcut.isReturnedByServer()) {
1637 Log.w(TAG,
1638 "Re-publishing ShortcutInfo returned by server is not supported."
1639 + " Some information such as icon may lost from shortcut.");
1640 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001641 Preconditions.checkNotNull(shortcut, "Null shortcut detected");
Makoto Onuki255461f2017-01-10 11:47:25 -08001642 if (shortcut.getActivity() != null) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001643 Preconditions.checkState(
Makoto Onuki22fcc682016-05-17 14:52:19 -07001644 shortcut.getPackage().equals(shortcut.getActivity().getPackageName()),
Makoto Onukib08790c2016-06-23 14:05:46 -07001645 "Cannot publish shortcut: activity " + shortcut.getActivity() + " does not"
1646 + " belong to package " + shortcut.getPackage());
Makoto Onuki13260b6ff2016-07-13 18:03:13 -07001647 Preconditions.checkState(
1648 injectIsMainActivity(shortcut.getActivity(), shortcut.getUserId()),
1649 "Cannot publish shortcut: activity " + shortcut.getActivity() + " is not"
1650 + " main activity");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001651 }
1652
Makoto Onuki55046222016-03-08 10:49:47 -08001653 if (!forUpdate) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001654 shortcut.enforceMandatoryFields(/* forPinned= */ forPinRequest);
1655 if (!forPinRequest) {
Makoto Onuki255461f2017-01-10 11:47:25 -08001656 Preconditions.checkState(shortcut.getActivity() != null,
1657 "Cannot publish shortcut: target activity is not set");
Makoto Onuki2d895c32016-12-02 15:48:40 -08001658 }
Makoto Onuki55046222016-03-08 10:49:47 -08001659 }
1660 if (shortcut.getIcon() != null) {
1661 ShortcutInfo.validateIcon(shortcut.getIcon());
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001662 }
1663
Makoto Onukide667372016-03-15 14:29:20 -07001664 shortcut.replaceFlags(0);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001665 }
1666
Makoto Onuki2d895c32016-12-02 15:48:40 -08001667 private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
1668 fixUpIncomingShortcutInfo(shortcut, forUpdate, /*forPinRequest=*/ false);
1669 }
1670
1671 public void validateShortcutForPinRequest(@NonNull ShortcutInfo shortcut) {
1672 fixUpIncomingShortcutInfo(shortcut, /* forUpdate= */ false, /*forPinRequest=*/ true);
1673 }
1674
Makoto Onukib08790c2016-06-23 14:05:46 -07001675 /**
1676 * When a shortcut has no target activity, set the default one from the package.
1677 */
1678 private void fillInDefaultActivity(List<ShortcutInfo> shortcuts) {
Makoto Onukib08790c2016-06-23 14:05:46 -07001679 ComponentName defaultActivity = null;
1680 for (int i = shortcuts.size() - 1; i >= 0; i--) {
1681 final ShortcutInfo si = shortcuts.get(i);
1682 if (si.getActivity() == null) {
1683 if (defaultActivity == null) {
1684 defaultActivity = injectGetDefaultMainActivity(
1685 si.getPackage(), si.getUserId());
1686 Preconditions.checkState(defaultActivity != null,
1687 "Launcher activity not found for package " + si.getPackage());
1688 }
1689 si.setActivity(defaultActivity);
1690 }
1691 }
1692 }
1693
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001694 private void assignImplicitRanks(List<ShortcutInfo> shortcuts) {
1695 for (int i = shortcuts.size() - 1; i >= 0; i--) {
1696 shortcuts.get(i).setImplicitRank(i);
1697 }
1698 }
1699
Makoto Onukibf563b62017-05-04 10:25:30 -07001700 private List<ShortcutInfo> setReturnedByServer(List<ShortcutInfo> shortcuts) {
1701 for (int i = shortcuts.size() - 1; i >= 0; i--) {
1702 shortcuts.get(i).setReturnedByServer();
1703 }
1704 return shortcuts;
1705 }
1706
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001707 // === APIs ===
1708
1709 @Override
1710 public boolean setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
1711 @UserIdInt int userId) {
1712 verifyCaller(packageName, userId);
1713
1714 final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
1715 final int size = newShortcuts.size();
1716
1717 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001718 throwIfUserLockedL(userId);
1719
Makoto Onukic8c33292016-09-12 16:36:59 -07001720 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001721
Makoto Onukia4f89b12017-10-05 10:37:55 -07001722 ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001723
Makoto Onukib08790c2016-06-23 14:05:46 -07001724 fillInDefaultActivity(newShortcuts);
1725
Makoto Onuki7001a612016-05-27 13:24:28 -07001726 ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_SET);
1727
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001728 // Throttling.
Makoto Onukic51b2872016-05-04 15:24:50 -07001729 if (!ps.tryApiCall()) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001730 return false;
1731 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001732
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001733 // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
1734 ps.clearAllImplicitRanks();
1735 assignImplicitRanks(newShortcuts);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001736
Makoto Onukidf6da042016-06-16 09:51:40 -07001737 for (int i = 0; i < size; i++) {
1738 fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false);
1739 }
1740
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001741 // First, remove all un-pinned; dynamic shortcuts
Makoto Onukia4f89b12017-10-05 10:37:55 -07001742 ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001743
1744 // Then, add/update all. We need to make sure to take over "pinned" flag.
1745 for (int i = 0; i < size; i++) {
1746 final ShortcutInfo newShortcut = newShortcuts.get(i);
Makoto Onukia4f89b12017-10-05 10:37:55 -07001747 ps.addOrReplaceDynamicShortcut(newShortcut);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001748 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001749
1750 // Lastly, adjust the ranks.
1751 ps.adjustRanks();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001752 }
Makoto Onuki39686e82016-04-13 18:03:00 -07001753 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07001754
1755 verifyStates();
1756
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001757 return true;
1758 }
1759
1760 @Override
1761 public boolean updateShortcuts(String packageName, ParceledListSlice shortcutInfoList,
1762 @UserIdInt int userId) {
1763 verifyCaller(packageName, userId);
1764
1765 final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
Makoto Onuki55046222016-03-08 10:49:47 -08001766 final int size = newShortcuts.size();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001767
1768 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001769 throwIfUserLockedL(userId);
1770
Makoto Onukic8c33292016-09-12 16:36:59 -07001771 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001772
Makoto Onukia4f89b12017-10-05 10:37:55 -07001773 ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001774
Makoto Onukib08790c2016-06-23 14:05:46 -07001775 // For update, don't fill in the default activity. Having null activity means
1776 // "don't update the activity" here.
1777
Makoto Onuki7001a612016-05-27 13:24:28 -07001778 ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_UPDATE);
1779
Makoto Onuki55046222016-03-08 10:49:47 -08001780 // Throttling.
Makoto Onukic51b2872016-05-04 15:24:50 -07001781 if (!ps.tryApiCall()) {
Makoto Onuki55046222016-03-08 10:49:47 -08001782 return false;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001783 }
1784
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001785 // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
1786 ps.clearAllImplicitRanks();
1787 assignImplicitRanks(newShortcuts);
1788
Makoto Onuki55046222016-03-08 10:49:47 -08001789 for (int i = 0; i < size; i++) {
1790 final ShortcutInfo source = newShortcuts.get(i);
1791 fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
1792
1793 final ShortcutInfo target = ps.findShortcutById(source.getId());
Makoto Onukia4f89b12017-10-05 10:37:55 -07001794
1795 // Invisible shortcuts can't be updated.
1796 if (target == null || !target.isVisibleToPublisher()) {
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001797 continue;
1798 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07001799
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001800 if (target.isEnabled() != source.isEnabled()) {
1801 Slog.w(TAG,
1802 "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
1803 }
Makoto Onuki55046222016-03-08 10:49:47 -08001804
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001805 // When updating the rank, we need to insert between existing ranks, so set
1806 // this setRankChanged, and also copy the implicit rank fo adjustRanks().
1807 if (source.hasRank()) {
1808 target.setRankChanged();
1809 target.setImplicitRank(source.getImplicitRank());
1810 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07001811
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001812 final boolean replacingIcon = (source.getIcon() != null);
1813 if (replacingIcon) {
Makoto Onuki475c3652017-05-08 14:29:03 -07001814 removeIconLocked(target);
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001815 }
Makoto Onuki55046222016-03-08 10:49:47 -08001816
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001817 // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
1818 target.copyNonNullFieldsFrom(source);
1819 target.setTimestamp(injectCurrentTimeMillis());
1820
1821 if (replacingIcon) {
Makoto Onuki475c3652017-05-08 14:29:03 -07001822 saveIconAndFixUpShortcutLocked(target);
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001823 }
1824
1825 // When we're updating any resource related fields, re-extract the res names and
1826 // the values.
1827 if (replacingIcon || source.hasStringResources()) {
1828 fixUpShortcutResourceNamesAndValues(target);
Makoto Onuki55046222016-03-08 10:49:47 -08001829 }
1830 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001831
1832 // Lastly, adjust the ranks.
1833 ps.adjustRanks();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001834 }
Makoto Onuki39686e82016-04-13 18:03:00 -07001835 packageShortcutsChanged(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001836
Makoto Onuki7001a612016-05-27 13:24:28 -07001837 verifyStates();
1838
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001839 return true;
1840 }
1841
1842 @Override
Makoto Onukia4f89b12017-10-05 10:37:55 -07001843 public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001844 @UserIdInt int userId) {
1845 verifyCaller(packageName, userId);
1846
Makoto Onukib6d35232016-04-04 15:57:17 -07001847 final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
1848 final int size = newShortcuts.size();
1849
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001850 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001851 throwIfUserLockedL(userId);
1852
Makoto Onukic8c33292016-09-12 16:36:59 -07001853 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001854
Makoto Onukia4f89b12017-10-05 10:37:55 -07001855 ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001856
Makoto Onukib08790c2016-06-23 14:05:46 -07001857 fillInDefaultActivity(newShortcuts);
1858
Makoto Onuki7001a612016-05-27 13:24:28 -07001859 ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_ADD);
1860
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001861 // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
1862 ps.clearAllImplicitRanks();
1863 assignImplicitRanks(newShortcuts);
1864
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001865 // Throttling.
Makoto Onukic51b2872016-05-04 15:24:50 -07001866 if (!ps.tryApiCall()) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001867 return false;
1868 }
Makoto Onukib6d35232016-04-04 15:57:17 -07001869 for (int i = 0; i < size; i++) {
1870 final ShortcutInfo newShortcut = newShortcuts.get(i);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001871
Makoto Onukib6d35232016-04-04 15:57:17 -07001872 // Validate the shortcut.
1873 fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001874
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001875 // When ranks are changing, we need to insert between ranks, so set the
1876 // "rank changed" flag.
1877 newShortcut.setRankChanged();
1878
Makoto Onukib6d35232016-04-04 15:57:17 -07001879 // Add it.
Makoto Onukia4f89b12017-10-05 10:37:55 -07001880 ps.addOrReplaceDynamicShortcut(newShortcut);
Makoto Onukib6d35232016-04-04 15:57:17 -07001881 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001882
1883 // Lastly, adjust the ranks.
1884 ps.adjustRanks();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001885 }
Makoto Onuki39686e82016-04-13 18:03:00 -07001886 packageShortcutsChanged(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001887
Makoto Onuki7001a612016-05-27 13:24:28 -07001888 verifyStates();
1889
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001890 return true;
1891 }
1892
1893 @Override
Makoto Onuki2d895c32016-12-02 15:48:40 -08001894 public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
1895 IntentSender resultIntent, int userId) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001896 Preconditions.checkNotNull(shortcut);
1897 Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001898 return requestPinItem(packageName, userId, shortcut, null, null, resultIntent);
Sunny Goyal87a563e2017-01-01 19:42:45 -08001899 }
1900
Sunny Goyala6be88a2017-01-12 16:27:58 -08001901 @Override
1902 public Intent createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId)
1903 throws RemoteException {
1904 Preconditions.checkNotNull(shortcut);
1905 Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
1906 verifyCaller(packageName, userId);
1907
1908 final Intent ret;
1909 synchronized (mLock) {
1910 throwIfUserLockedL(userId);
1911
1912 // Send request to the launcher, if supported.
1913 ret = mShortcutRequestPinProcessor.createShortcutResultIntent(shortcut, userId);
1914 }
1915
1916 verifyStates();
1917 return ret;
1918 }
1919
Sunny Goyal87a563e2017-01-01 19:42:45 -08001920 /**
1921 * Handles {@link #requestPinShortcut} and {@link ShortcutServiceInternal#requestPinAppWidget}.
1922 * After validating the caller, it passes the request to {@link #mShortcutRequestPinProcessor}.
1923 * Either {@param shortcut} or {@param appWidget} should be non-null.
1924 */
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001925 private boolean requestPinItem(String packageName, int userId, ShortcutInfo shortcut,
1926 AppWidgetProviderInfo appWidget, Bundle extras, IntentSender resultIntent) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08001927 verifyCaller(packageName, userId);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001928
1929 final boolean ret;
1930 synchronized (mLock) {
1931 throwIfUserLockedL(userId);
1932
Makoto Onukia01f4f02016-12-15 15:58:41 -08001933 Preconditions.checkState(isUidForegroundLocked(injectBinderCallingUid()),
Makoto Onuki255461f2017-01-10 11:47:25 -08001934 "Calling application must have a foreground activity or a foreground service");
Makoto Onuki2d895c32016-12-02 15:48:40 -08001935
Makoto Onukia4f89b12017-10-05 10:37:55 -07001936 // If it's a pin shortcut request, and there's already a shortcut with the same ID
1937 // that's not visible to the caller (i.e. restore-blocked; meaning it's pinned by
1938 // someone already), then we just replace the existing one with this new one,
1939 // and then proceed the rest of the process.
1940 if (shortcut != null) {
1941 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(
1942 packageName, userId);
1943 final String id = shortcut.getId();
1944 if (ps.isShortcutExistsAndInvisibleToPublisher(id)) {
1945
1946 ps.updateInvisibleShortcutForPinRequestWith(shortcut);
1947
1948 packageShortcutsChanged(packageName, userId);
1949 }
1950 }
1951
Makoto Onuki2d895c32016-12-02 15:48:40 -08001952 // Send request to the launcher, if supported.
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001953 ret = mShortcutRequestPinProcessor.requestPinItemLocked(shortcut, appWidget, extras,
1954 userId, resultIntent);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001955 }
1956
1957 verifyStates();
1958
1959 return ret;
1960 }
1961
1962 @Override
Makoto Onuki20c95f82016-05-11 16:51:01 -07001963 public void disableShortcuts(String packageName, List shortcutIds,
Makoto Onukid6880792016-06-29 13:37:43 -07001964 CharSequence disabledMessage, int disabledMessageResId, @UserIdInt int userId) {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001965 verifyCaller(packageName, userId);
1966 Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
1967
1968 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001969 throwIfUserLockedL(userId);
1970
Makoto Onukic8c33292016-09-12 16:36:59 -07001971 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001972
Makoto Onukia4f89b12017-10-05 10:37:55 -07001973 ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
1974 /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001975
Makoto Onukid6880792016-06-29 13:37:43 -07001976 final String disabledMessageString =
1977 (disabledMessage == null) ? null : disabledMessage.toString();
1978
Makoto Onuki22fcc682016-05-17 14:52:19 -07001979 for (int i = shortcutIds.size() - 1; i >= 0; i--) {
Makoto Onukia4f89b12017-10-05 10:37:55 -07001980 final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
1981 if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
1982 continue;
1983 }
1984 ps.disableWithId(id,
Makoto Onukid6880792016-06-29 13:37:43 -07001985 disabledMessageString, disabledMessageResId,
Makoto Onukia4f89b12017-10-05 10:37:55 -07001986 /* overrideImmutable=*/ false, /*ignoreInvisible=*/ true,
1987 ShortcutInfo.DISABLED_REASON_BY_APP);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001988 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001989
1990 // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
1991 ps.adjustRanks();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001992 }
1993 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07001994
1995 verifyStates();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001996 }
1997
1998 @Override
1999 public void enableShortcuts(String packageName, List shortcutIds, @UserIdInt int userId) {
2000 verifyCaller(packageName, userId);
2001 Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
2002
2003 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002004 throwIfUserLockedL(userId);
2005
Makoto Onukic8c33292016-09-12 16:36:59 -07002006 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002007
Makoto Onukia4f89b12017-10-05 10:37:55 -07002008 ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
2009 /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002010
2011 for (int i = shortcutIds.size() - 1; i >= 0; i--) {
Makoto Onukia4f89b12017-10-05 10:37:55 -07002012 final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
2013 if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
2014 continue;
2015 }
2016 ps.enableWithId(id);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002017 }
Makoto Onuki20c95f82016-05-11 16:51:01 -07002018 }
2019 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002020
2021 verifyStates();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002022 }
2023
2024 @Override
Makoto Onukib6d35232016-04-04 15:57:17 -07002025 public void removeDynamicShortcuts(String packageName, List shortcutIds,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002026 @UserIdInt int userId) {
2027 verifyCaller(packageName, userId);
Makoto Onukib6d35232016-04-04 15:57:17 -07002028 Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002029
2030 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002031 throwIfUserLockedL(userId);
2032
Makoto Onukic8c33292016-09-12 16:36:59 -07002033 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002034
Makoto Onukia4f89b12017-10-05 10:37:55 -07002035 ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
2036 /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002037
Makoto Onukib6d35232016-04-04 15:57:17 -07002038 for (int i = shortcutIds.size() - 1; i >= 0; i--) {
Makoto Onukia4f89b12017-10-05 10:37:55 -07002039 final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
2040 if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
2041 continue;
2042 }
2043 ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true);
Makoto Onukib6d35232016-04-04 15:57:17 -07002044 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07002045
2046 // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
2047 ps.adjustRanks();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002048 }
Makoto Onuki39686e82016-04-13 18:03:00 -07002049 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002050
2051 verifyStates();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002052 }
2053
2054 @Override
Makoto Onukib6d35232016-04-04 15:57:17 -07002055 public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002056 verifyCaller(packageName, userId);
2057
2058 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002059 throwIfUserLockedL(userId);
2060
Makoto Onukic8c33292016-09-12 16:36:59 -07002061 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onukia4f89b12017-10-05 10:37:55 -07002062 ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002063 }
Makoto Onuki39686e82016-04-13 18:03:00 -07002064 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002065
2066 verifyStates();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002067 }
2068
2069 @Override
2070 public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName,
2071 @UserIdInt int userId) {
2072 verifyCaller(packageName, userId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002073
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002074 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002075 throwIfUserLockedL(userId);
2076
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002077 return getShortcutsWithQueryLocked(
2078 packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
Makoto Onukia4f89b12017-10-05 10:37:55 -07002079 ShortcutInfo::isDynamicVisible);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002080 }
2081 }
2082
2083 @Override
Makoto Onuki22fcc682016-05-17 14:52:19 -07002084 public ParceledListSlice<ShortcutInfo> getManifestShortcuts(String packageName,
2085 @UserIdInt int userId) {
2086 verifyCaller(packageName, userId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002087
Makoto Onuki22fcc682016-05-17 14:52:19 -07002088 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002089 throwIfUserLockedL(userId);
2090
Makoto Onuki22fcc682016-05-17 14:52:19 -07002091 return getShortcutsWithQueryLocked(
2092 packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
Makoto Onukia4f89b12017-10-05 10:37:55 -07002093 ShortcutInfo::isManifestVisible);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002094 }
2095 }
2096
2097 @Override
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002098 public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName,
2099 @UserIdInt int userId) {
2100 verifyCaller(packageName, userId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002101
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002102 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002103 throwIfUserLockedL(userId);
2104
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002105 return getShortcutsWithQueryLocked(
2106 packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
Makoto Onukia4f89b12017-10-05 10:37:55 -07002107 ShortcutInfo::isPinnedVisible);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002108 }
2109 }
2110
2111 private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
2112 @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
2113
2114 final ArrayList<ShortcutInfo> ret = new ArrayList<>();
2115
Makoto Onukic8c33292016-09-12 16:36:59 -07002116 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002117 ps.findAll(ret, query, cloneFlags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002118
Makoto Onukibf563b62017-05-04 10:25:30 -07002119 return new ParceledListSlice<>(setReturnedByServer(ret));
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002120 }
2121
2122 @Override
Makoto Onukid6880792016-06-29 13:37:43 -07002123 public int getMaxShortcutCountPerActivity(String packageName, @UserIdInt int userId)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002124 throws RemoteException {
2125 verifyCaller(packageName, userId);
2126
Makoto Onukib5a012f2016-06-21 11:13:53 -07002127 return mMaxShortcuts;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002128 }
2129
2130 @Override
2131 public int getRemainingCallCount(String packageName, @UserIdInt int userId) {
2132 verifyCaller(packageName, userId);
2133
2134 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002135 throwIfUserLockedL(userId);
2136
Makoto Onukic8c33292016-09-12 16:36:59 -07002137 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002138 return mMaxUpdatesPerInterval - ps.getApiCallCount();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002139 }
2140 }
2141
2142 @Override
2143 public long getRateLimitResetTime(String packageName, @UserIdInt int userId) {
2144 verifyCaller(packageName, userId);
2145
2146 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002147 throwIfUserLockedL(userId);
2148
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002149 return getNextResetTimeLocked();
2150 }
2151 }
2152
Makoto Onuki55046222016-03-08 10:49:47 -08002153 @Override
Makoto Onuki20c95f82016-05-11 16:51:01 -07002154 public int getIconMaxDimensions(String packageName, int userId) {
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07002155 verifyCaller(packageName, userId);
2156
Makoto Onuki55046222016-03-08 10:49:47 -08002157 synchronized (mLock) {
2158 return mMaxIconDimension;
2159 }
2160 }
2161
Makoto Onuki20c95f82016-05-11 16:51:01 -07002162 @Override
2163 public void reportShortcutUsed(String packageName, String shortcutId, int userId) {
2164 verifyCaller(packageName, userId);
2165
Makoto Onukiac042502016-05-20 16:39:42 -07002166 Preconditions.checkNotNull(shortcutId);
2167
2168 if (DEBUG) {
2169 Slog.d(TAG, String.format("reportShortcutUsed: Shortcut %s package %s used on user %d",
2170 shortcutId, packageName, userId));
2171 }
2172
2173 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002174 throwIfUserLockedL(userId);
2175
Makoto Onukic8c33292016-09-12 16:36:59 -07002176 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002177
Makoto Onukiac042502016-05-20 16:39:42 -07002178 if (ps.findShortcutById(shortcutId) == null) {
2179 Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
2180 packageName, shortcutId));
2181 return;
2182 }
2183 }
2184
2185 final long token = injectClearCallingIdentity();
2186 try {
2187 mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId);
2188 } finally {
2189 injectRestoreCallingIdentity(token);
2190 }
Makoto Onuki20c95f82016-05-11 16:51:01 -07002191 }
2192
Makoto Onuki2d895c32016-12-02 15:48:40 -08002193 @Override
Sunny Goyal7f7372a2017-01-24 11:53:54 -08002194 public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08002195 final long token = injectClearCallingIdentity();
2196 try {
Sunny Goyal7f7372a2017-01-24 11:53:54 -08002197 return mShortcutRequestPinProcessor
2198 .isRequestPinItemSupported(callingUserId, requestType);
Makoto Onuki2d895c32016-12-02 15:48:40 -08002199 } finally {
2200 injectRestoreCallingIdentity(token);
2201 }
2202 }
2203
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002204 /**
Makoto Onukib08790c2016-06-23 14:05:46 -07002205 * Reset all throttling, for developer options and command line. Only system/shell can call
2206 * it.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002207 */
2208 @Override
2209 public void resetThrottling() {
2210 enforceSystemOrShell();
2211
Makoto Onuki4554d0e2016-03-14 15:51:41 -07002212 resetThrottlingInner(getCallingUserId());
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002213 }
2214
Makoto Onuki4554d0e2016-03-14 15:51:41 -07002215 void resetThrottlingInner(@UserIdInt int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002216 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002217 if (!isUserUnlockedL(userId)) {
2218 Log.w(TAG, "User " + userId + " is locked or not running");
2219 return;
2220 }
2221
Makoto Onuki4554d0e2016-03-14 15:51:41 -07002222 getUserShortcutsLocked(userId).resetThrottling();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002223 }
Makoto Onuki4554d0e2016-03-14 15:51:41 -07002224 scheduleSaveUser(userId);
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07002225 Slog.i(TAG, "ShortcutManager: throttling counter reset for user " + userId);
2226 }
2227
2228 void resetAllThrottlingInner() {
2229 synchronized (mLock) {
2230 mRawLastResetTime = injectCurrentTimeMillis();
2231 }
2232 scheduleSaveBaseState();
2233 Slog.i(TAG, "ShortcutManager: throttling counter reset for all users");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002234 }
2235
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002236 @Override
2237 public void onApplicationActive(String packageName, int userId) {
2238 if (DEBUG) {
2239 Slog.d(TAG, "onApplicationActive: package=" + packageName + " userid=" + userId);
2240 }
2241 enforceResetThrottlingPermission();
Makoto Onuki02f338e2016-07-29 09:40:40 -07002242
2243 synchronized (mLock) {
2244 if (!isUserUnlockedL(userId)) {
2245 // This is called by system UI, so no need to throw. Just ignore.
2246 return;
2247 }
2248
2249 getPackageShortcutsLocked(packageName, userId)
2250 .resetRateLimitingForCommandLineNoSaving();
2251 saveUserLocked(userId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002252 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002253 }
2254
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002255 // We override this method in unit tests to do a simpler check.
Makoto Onuki634cecb2017-10-13 17:10:48 -07002256 boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId,
2257 int callingPid, int callingUid) {
Makoto Onuki35559d62017-11-06 16:26:32 -08002258 if (canSeeAnyPinnedShortcut(callingPackage, userId, callingPid, callingUid)) {
Makoto Onuki634cecb2017-10-13 17:10:48 -07002259 return true;
2260 }
Makoto Onuki84d59342018-02-02 09:22:38 -08002261 final long start = getStatStartTime();
Makoto Onuki10305202016-07-14 18:14:08 -07002262 try {
2263 return hasShortcutHostPermissionInner(callingPackage, userId);
2264 } finally {
2265 logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
2266 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002267 }
2268
Makoto Onuki35559d62017-11-06 16:26:32 -08002269 boolean canSeeAnyPinnedShortcut(@NonNull String callingPackage, int userId,
2270 int callingPid, int callingUid) {
2271 if (injectHasAccessShortcutsPermission(callingPid, callingUid)) {
2272 return true;
2273 }
2274 synchronized (mLock) {
Makoto Onuki708703b2017-12-11 16:38:11 -08002275 return getNonPersistentUserLocked(userId).hasHostPackage(callingPackage);
Makoto Onuki35559d62017-11-06 16:26:32 -08002276 }
2277 }
2278
Makoto Onuki634cecb2017-10-13 17:10:48 -07002279 /**
2280 * Returns true if the caller has the "ACCESS_SHORTCUTS" permission.
2281 */
Makoto Onuki35559d62017-11-06 16:26:32 -08002282 @VisibleForTesting
2283 boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
Makoto Onuki634cecb2017-10-13 17:10:48 -07002284 return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS,
2285 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
2286 }
2287
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002288 // This method is extracted so we can directly call this method from unit tests,
2289 // even when hasShortcutPermission() is overridden.
2290 @VisibleForTesting
Makoto Onuki2d895c32016-12-02 15:48:40 -08002291 boolean hasShortcutHostPermissionInner(@NonNull String packageName, int userId) {
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002292 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002293 throwIfUserLockedL(userId);
2294
Makoto Onuki31459242016-03-22 11:12:18 -07002295 final ShortcutUser user = getUserShortcutsLocked(userId);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002296
Makoto Onuki2d895c32016-12-02 15:48:40 -08002297 // Always trust the cached component.
Makoto Onuki10305202016-07-14 18:14:08 -07002298 final ComponentName cached = user.getCachedLauncher();
2299 if (cached != null) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08002300 if (cached.getPackageName().equals(packageName)) {
Makoto Onuki10305202016-07-14 18:14:08 -07002301 return true;
2302 }
2303 }
2304 // If the cached one doesn't match, then go ahead
2305
Makoto Onuki2d895c32016-12-02 15:48:40 -08002306 final ComponentName detected = getDefaultLauncher(userId);
Makoto Onuki2e210c42016-03-30 08:30:36 -07002307
Makoto Onuki10305202016-07-14 18:14:08 -07002308 // Update the cache.
2309 user.setLauncher(detected);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002310 if (detected != null) {
2311 if (DEBUG) {
2312 Slog.v(TAG, "Detected launcher: " + detected);
2313 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08002314 return detected.getPackageName().equals(packageName);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002315 } else {
2316 // Default launcher not found.
2317 return false;
2318 }
2319 }
2320 }
2321
Makoto Onuki2d895c32016-12-02 15:48:40 -08002322 @Nullable
2323 ComponentName getDefaultLauncher(@UserIdInt int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08002324 final long start = getStatStartTime();
Makoto Onuki2d895c32016-12-02 15:48:40 -08002325 final long token = injectClearCallingIdentity();
2326 try {
2327 synchronized (mLock) {
2328 throwIfUserLockedL(userId);
2329
2330 final ShortcutUser user = getUserShortcutsLocked(userId);
2331
2332 final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
2333
2334 // Default launcher from package manager.
Makoto Onuki84d59342018-02-02 09:22:38 -08002335 final long startGetHomeActivitiesAsUser = getStatStartTime();
Makoto Onuki2d895c32016-12-02 15:48:40 -08002336 final ComponentName defaultLauncher = mPackageManagerInternal
2337 .getHomeActivitiesAsUser(allHomeCandidates, userId);
2338 logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
2339
2340 ComponentName detected = null;
2341 if (defaultLauncher != null) {
2342 detected = defaultLauncher;
2343 if (DEBUG) {
2344 Slog.v(TAG, "Default launcher from PM: " + detected);
2345 }
2346 } else {
2347 detected = user.getLastKnownLauncher();
2348
2349 if (detected != null) {
2350 if (injectIsActivityEnabledAndExported(detected, userId)) {
2351 if (DEBUG) {
2352 Slog.v(TAG, "Cached launcher: " + detected);
2353 }
2354 } else {
2355 Slog.w(TAG, "Cached launcher " + detected + " no longer exists");
2356 detected = null;
2357 user.clearLauncher();
2358 }
2359 }
2360 }
2361
2362 if (detected == null) {
2363 // If we reach here, that means it's the first check since the user was created,
2364 // and there's already multiple launchers and there's no default set.
2365 // Find the system one with the highest priority.
2366 // (We need to check the priority too because of FallbackHome in Settings.)
2367 // If there's no system launcher yet, then no one can access shortcuts, until
2368 // the user explicitly
2369 final int size = allHomeCandidates.size();
2370
2371 int lastPriority = Integer.MIN_VALUE;
2372 for (int i = 0; i < size; i++) {
2373 final ResolveInfo ri = allHomeCandidates.get(i);
2374 if (!ri.activityInfo.applicationInfo.isSystemApp()) {
2375 continue;
2376 }
2377 if (DEBUG) {
2378 Slog.d(TAG, String.format("hasShortcutPermissionInner: pkg=%s prio=%d",
2379 ri.activityInfo.getComponentName(), ri.priority));
2380 }
2381 if (ri.priority < lastPriority) {
2382 continue;
2383 }
2384 detected = ri.activityInfo.getComponentName();
2385 lastPriority = ri.priority;
2386 }
2387 }
2388 return detected;
2389 }
2390 } finally {
2391 injectRestoreCallingIdentity(token);
2392 logDurationStat(Stats.GET_DEFAULT_LAUNCHER, start);
2393 }
2394 }
2395
Dianne Hackbornc160fa42017-11-01 16:14:26 -07002396 public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
2397 int userId) {
2398 synchronized (mLock) {
Makoto Onuki708703b2017-12-11 16:38:11 -08002399 getNonPersistentUserLocked(userId).setShortcutHostPackage(type, packageName);
Dianne Hackbornc160fa42017-11-01 16:14:26 -07002400 }
2401 }
2402
Makoto Onukicdc78f72016-03-21 15:47:52 -07002403 // === House keeping ===
2404
Makoto Onukib08790c2016-06-23 14:05:46 -07002405 private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
2406 boolean appStillExists) {
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002407 synchronized (mLock) {
2408 forEachLoadedUserLocked(user ->
Makoto Onukib08790c2016-06-23 14:05:46 -07002409 cleanUpPackageLocked(packageName, user.getUserId(), packageUserId,
2410 appStillExists));
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002411 }
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07002412 }
2413
Makoto Onuki2e210c42016-03-30 08:30:36 -07002414 /**
2415 * Remove all the information associated with a package. This will really remove all the
2416 * information, including the restore information (i.e. it'll remove packages even if they're
2417 * shadow).
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002418 *
2419 * This is called when an app is uninstalled, or an app gets "clear data"ed.
Makoto Onuki2e210c42016-03-30 08:30:36 -07002420 */
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002421 @VisibleForTesting
Makoto Onukib08790c2016-06-23 14:05:46 -07002422 void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId,
2423 boolean appStillExists) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002424 final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002425
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002426 final ShortcutUser user = getUserShortcutsLocked(owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002427 boolean doNotify = false;
2428
2429 // First, remove the package from the package list (if the package is a publisher).
Makoto Onukid99c6f02016-03-28 11:02:54 -07002430 if (packageUserId == owningUserId) {
Makoto Onukic51b2872016-05-04 15:24:50 -07002431 if (user.removePackage(packageName) != null) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002432 doNotify = true;
2433 }
Makoto Onukicdc78f72016-03-21 15:47:52 -07002434 }
Makoto Onukid99c6f02016-03-28 11:02:54 -07002435
Makoto Onukicdc78f72016-03-21 15:47:52 -07002436 // Also remove from the launcher list (if the package is a launcher).
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002437 user.removeLauncher(packageUserId, packageName);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002438
2439 // Then remove pinned shortcuts from all launchers.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002440 user.forAllLaunchers(l -> l.cleanUpPackage(packageName, packageUserId));
2441
2442 // Now there may be orphan shortcuts because we removed pinned shortcuts at the previous
Makoto Onukicdc78f72016-03-21 15:47:52 -07002443 // step. Remove them too.
Makoto Onukic51b2872016-05-04 15:24:50 -07002444 user.forAllPackages(p -> p.refreshPinnedFlags());
Makoto Onukicdc78f72016-03-21 15:47:52 -07002445
Makoto Onukid99c6f02016-03-28 11:02:54 -07002446 scheduleSaveUser(owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002447
2448 if (doNotify) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002449 notifyListeners(packageName, owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002450 }
2451
Makoto Onukib08790c2016-06-23 14:05:46 -07002452 // If the app still exists (i.e. data cleared), we need to re-publish manifest shortcuts.
2453 if (appStillExists && (packageUserId == owningUserId)) {
2454 // This will do the notification and save when needed, so do it after the above
2455 // notifyListeners.
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002456 user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
Makoto Onukib08790c2016-06-23 14:05:46 -07002457 }
2458
Makoto Onukicdc78f72016-03-21 15:47:52 -07002459 if (!wasUserLoaded) {
2460 // Note this will execute the scheduled save.
Makoto Onukid99c6f02016-03-28 11:02:54 -07002461 unloadUserLocked(owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002462 }
2463 }
2464
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002465 /**
2466 * Entry point from {@link LauncherApps}.
2467 */
2468 private class LocalService extends ShortcutServiceInternal {
Makoto Onuki2e210c42016-03-30 08:30:36 -07002469
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002470 @Override
Makoto Onukid99c6f02016-03-28 11:02:54 -07002471 public List<ShortcutInfo> getShortcuts(int launcherUserId,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002472 @NonNull String callingPackage, long changedSince,
Makoto Onukiabe84422016-04-07 09:41:19 -07002473 @Nullable String packageName, @Nullable List<String> shortcutIds,
Makoto Onuki99302b52017-03-29 12:42:26 -07002474 @Nullable ComponentName componentName,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002475 int queryFlags, int userId, int callingPid, int callingUid) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002476 final ArrayList<ShortcutInfo> ret = new ArrayList<>();
Makoto Onuki9c850012016-07-26 15:50:50 -07002477
Makoto Onuki20c95f82016-05-11 16:51:01 -07002478 final boolean cloneKeyFieldOnly =
2479 ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
2480 final int cloneFlag = cloneKeyFieldOnly ? ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO
2481 : ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER;
Makoto Onukiabe84422016-04-07 09:41:19 -07002482 if (packageName == null) {
2483 shortcutIds = null; // LauncherAppsService already threw for it though.
2484 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002485
2486 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002487 throwIfUserLockedL(userId);
2488 throwIfUserLockedL(launcherUserId);
2489
Makoto Onuki2e210c42016-03-30 08:30:36 -07002490 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002491 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002492
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002493 if (packageName != null) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002494 getShortcutsInnerLocked(launcherUserId,
Makoto Onukiabe84422016-04-07 09:41:19 -07002495 callingPackage, packageName, shortcutIds, changedSince,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002496 componentName, queryFlags, userId, ret, cloneFlag,
2497 callingPid, callingUid);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002498 } else {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002499 final List<String> shortcutIdsF = shortcutIds;
2500 getUserShortcutsLocked(userId).forAllPackages(p -> {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002501 getShortcutsInnerLocked(launcherUserId,
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002502 callingPackage, p.getPackageName(), shortcutIdsF, changedSince,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002503 componentName, queryFlags, userId, ret, cloneFlag,
2504 callingPid, callingUid);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002505 });
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002506 }
2507 }
Makoto Onukibf563b62017-05-04 10:25:30 -07002508 return setReturnedByServer(ret);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002509 }
2510
Makoto Onukid99c6f02016-03-28 11:02:54 -07002511 private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
Makoto Onukiabe84422016-04-07 09:41:19 -07002512 @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
Makoto Onuki99302b52017-03-29 12:42:26 -07002513 @Nullable ComponentName componentName, int queryFlags,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002514 int userId, ArrayList<ShortcutInfo> ret, int cloneFlag,
2515 int callingPid, int callingUid) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002516 final ArraySet<String> ids = shortcutIds == null ? null
2517 : new ArraySet<>(shortcutIds);
2518
Makoto Onuki35559d62017-11-06 16:26:32 -08002519 final ShortcutUser user = getUserShortcutsLocked(userId);
2520 final ShortcutPackage p = user.getPackageShortcutsIfExists(packageName);
Makoto Onukic51b2872016-05-04 15:24:50 -07002521 if (p == null) {
2522 return; // No need to instantiate ShortcutPackage.
2523 }
Makoto Onuki634cecb2017-10-13 17:10:48 -07002524 final boolean matchDynamic = (queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0;
2525 final boolean matchPinned = (queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
2526 final boolean matchManifest = (queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
2527
Makoto Onuki35559d62017-11-06 16:26:32 -08002528 final boolean canAccessAllShortcuts =
2529 canSeeAnyPinnedShortcut(callingPackage, launcherUserId, callingPid, callingUid);
2530
Makoto Onuki634cecb2017-10-13 17:10:48 -07002531 final boolean getPinnedByAnyLauncher =
Makoto Onuki35559d62017-11-06 16:26:32 -08002532 canAccessAllShortcuts &&
2533 ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER) != 0);
Makoto Onukic51b2872016-05-04 15:24:50 -07002534
2535 p.findAll(ret,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002536 (ShortcutInfo si) -> {
2537 if (si.getLastChangedTimestamp() < changedSince) {
2538 return false;
2539 }
Makoto Onukiabe84422016-04-07 09:41:19 -07002540 if (ids != null && !ids.contains(si.getId())) {
2541 return false;
2542 }
Makoto Onuki85694522016-05-04 12:53:37 -07002543 if (componentName != null) {
Makoto Onuki9fd90192017-01-06 18:31:03 +00002544 if (si.getActivity() != null
2545 && !si.getActivity().equals(componentName)) {
Makoto Onuki85694522016-05-04 12:53:37 -07002546 return false;
2547 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002548 }
Makoto Onuki634cecb2017-10-13 17:10:48 -07002549 if (matchDynamic && si.isDynamic()) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002550 return true;
2551 }
Makoto Onuki35559d62017-11-06 16:26:32 -08002552 if ((matchPinned || getPinnedByAnyLauncher) && si.isPinned()) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002553 return true;
2554 }
Makoto Onuki634cecb2017-10-13 17:10:48 -07002555 if (matchManifest && si.isDeclaredInManifest()) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002556 return true;
2557 }
2558 return false;
Makoto Onuki634cecb2017-10-13 17:10:48 -07002559 }, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002560 }
2561
2562 @Override
Makoto Onukid99c6f02016-03-28 11:02:54 -07002563 public boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
2564 @NonNull String packageName, @NonNull String shortcutId, int userId) {
2565 Preconditions.checkStringNotEmpty(packageName, "packageName");
2566 Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
2567
2568 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002569 throwIfUserLockedL(userId);
2570 throwIfUserLockedL(launcherUserId);
2571
Makoto Onuki2e210c42016-03-30 08:30:36 -07002572 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002573 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002574
Makoto Onukid99c6f02016-03-28 11:02:54 -07002575 final ShortcutInfo si = getShortcutInfoLocked(
Makoto Onuki634cecb2017-10-13 17:10:48 -07002576 launcherUserId, callingPackage, packageName, shortcutId, userId,
2577 /*getPinnedByAnyLauncher=*/ false);
Makoto Onukid99c6f02016-03-28 11:02:54 -07002578 return si != null && si.isPinned();
2579 }
2580 }
2581
Makoto Onuki2e210c42016-03-30 08:30:36 -07002582 private ShortcutInfo getShortcutInfoLocked(
Makoto Onukid99c6f02016-03-28 11:02:54 -07002583 int launcherUserId, @NonNull String callingPackage,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002584 @NonNull String packageName, @NonNull String shortcutId, int userId,
2585 boolean getPinnedByAnyLauncher) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002586 Preconditions.checkStringNotEmpty(packageName, "packageName");
2587 Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
2588
Makoto Onuki02f338e2016-07-29 09:40:40 -07002589 throwIfUserLockedL(userId);
2590 throwIfUserLockedL(launcherUserId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002591
Makoto Onukic51b2872016-05-04 15:24:50 -07002592 final ShortcutPackage p = getUserShortcutsLocked(userId)
2593 .getPackageShortcutsIfExists(packageName);
2594 if (p == null) {
2595 return null;
2596 }
2597
Makoto Onukid99c6f02016-03-28 11:02:54 -07002598 final ArrayList<ShortcutInfo> list = new ArrayList<>(1);
Makoto Onukic51b2872016-05-04 15:24:50 -07002599 p.findAll(list,
Makoto Onukid99c6f02016-03-28 11:02:54 -07002600 (ShortcutInfo si) -> shortcutId.equals(si.getId()),
Makoto Onuki634cecb2017-10-13 17:10:48 -07002601 /* clone flags=*/ 0, callingPackage, launcherUserId, getPinnedByAnyLauncher);
Makoto Onukid99c6f02016-03-28 11:02:54 -07002602 return list.size() == 0 ? null : list.get(0);
2603 }
2604
2605 @Override
2606 public void pinShortcuts(int launcherUserId,
2607 @NonNull String callingPackage, @NonNull String packageName,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002608 @NonNull List<String> shortcutIds, int userId) {
2609 // Calling permission must be checked by LauncherAppsImpl.
2610 Preconditions.checkStringNotEmpty(packageName, "packageName");
2611 Preconditions.checkNotNull(shortcutIds, "shortcutIds");
2612
2613 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002614 throwIfUserLockedL(userId);
2615 throwIfUserLockedL(launcherUserId);
2616
Makoto Onuki9da23fc2016-03-29 11:14:42 -07002617 final ShortcutLauncher launcher =
Makoto Onuki2e210c42016-03-30 08:30:36 -07002618 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
Makoto Onukic51b2872016-05-04 15:24:50 -07002619 launcher.attemptToRestoreIfNeededAndSave();
Makoto Onuki9da23fc2016-03-29 11:14:42 -07002620
Makoto Onukia4f89b12017-10-05 10:37:55 -07002621 launcher.pinShortcuts(userId, packageName, shortcutIds, /*forPinRequest=*/ false);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002622 }
Makoto Onuki39686e82016-04-13 18:03:00 -07002623 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002624
2625 verifyStates();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002626 }
2627
2628 @Override
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002629 public Intent[] createShortcutIntents(int launcherUserId,
Makoto Onukid99c6f02016-03-28 11:02:54 -07002630 @NonNull String callingPackage,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002631 @NonNull String packageName, @NonNull String shortcutId, int userId,
2632 int callingPid, int callingUid) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002633 // Calling permission must be checked by LauncherAppsImpl.
Makoto Onuki43204b82016-03-08 16:16:44 -08002634 Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
2635 Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002636
2637 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002638 throwIfUserLockedL(userId);
2639 throwIfUserLockedL(launcherUserId);
2640
Makoto Onuki2e210c42016-03-30 08:30:36 -07002641 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002642 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002643
Makoto Onuki634cecb2017-10-13 17:10:48 -07002644 final boolean getPinnedByAnyLauncher =
Makoto Onuki35559d62017-11-06 16:26:32 -08002645 canSeeAnyPinnedShortcut(callingPackage, launcherUserId,
2646 callingPid, callingUid);
Makoto Onuki634cecb2017-10-13 17:10:48 -07002647
Makoto Onukid99c6f02016-03-28 11:02:54 -07002648 // Make sure the shortcut is actually visible to the launcher.
2649 final ShortcutInfo si = getShortcutInfoLocked(
Makoto Onuki634cecb2017-10-13 17:10:48 -07002650 launcherUserId, callingPackage, packageName, shortcutId, userId,
2651 getPinnedByAnyLauncher);
Makoto Onukid99c6f02016-03-28 11:02:54 -07002652 // "si == null" should suffice here, but check the flags too just to make sure.
Makoto Onuki35559d62017-11-06 16:26:32 -08002653 if (si == null || !si.isEnabled() || !(si.isAlive() || getPinnedByAnyLauncher)) {
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07002654 Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
Makoto Onukid99c6f02016-03-28 11:02:54 -07002655 return null;
2656 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002657 return si.getIntents();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002658 }
2659 }
2660
2661 @Override
2662 public void addListener(@NonNull ShortcutChangeListener listener) {
2663 synchronized (mLock) {
2664 mListeners.add(Preconditions.checkNotNull(listener));
2665 }
2666 }
Makoto Onuki55046222016-03-08 10:49:47 -08002667
2668 @Override
Makoto Onukiabe84422016-04-07 09:41:19 -07002669 public int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
2670 @NonNull String packageName, @NonNull String shortcutId, int userId) {
2671 Preconditions.checkNotNull(callingPackage, "callingPackage");
2672 Preconditions.checkNotNull(packageName, "packageName");
2673 Preconditions.checkNotNull(shortcutId, "shortcutId");
Makoto Onuki55046222016-03-08 10:49:47 -08002674
2675 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002676 throwIfUserLockedL(userId);
2677 throwIfUserLockedL(launcherUserId);
2678
Makoto Onuki2e210c42016-03-30 08:30:36 -07002679 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002680 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002681
Makoto Onukic51b2872016-05-04 15:24:50 -07002682 final ShortcutPackage p = getUserShortcutsLocked(userId)
2683 .getPackageShortcutsIfExists(packageName);
2684 if (p == null) {
2685 return 0;
2686 }
2687
2688 final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
Makoto Onuki55046222016-03-08 10:49:47 -08002689 return (shortcutInfo != null && shortcutInfo.hasIconResource())
2690 ? shortcutInfo.getIconResourceId() : 0;
2691 }
2692 }
2693
2694 @Override
Makoto Onukid99c6f02016-03-28 11:02:54 -07002695 public ParcelFileDescriptor getShortcutIconFd(int launcherUserId,
Makoto Onukiabe84422016-04-07 09:41:19 -07002696 @NonNull String callingPackage, @NonNull String packageName,
2697 @NonNull String shortcutId, int userId) {
2698 Preconditions.checkNotNull(callingPackage, "callingPackage");
2699 Preconditions.checkNotNull(packageName, "packageName");
2700 Preconditions.checkNotNull(shortcutId, "shortcutId");
Makoto Onuki55046222016-03-08 10:49:47 -08002701
2702 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002703 throwIfUserLockedL(userId);
2704 throwIfUserLockedL(launcherUserId);
2705
Makoto Onuki2e210c42016-03-30 08:30:36 -07002706 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002707 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002708
Makoto Onukic51b2872016-05-04 15:24:50 -07002709 final ShortcutPackage p = getUserShortcutsLocked(userId)
2710 .getPackageShortcutsIfExists(packageName);
2711 if (p == null) {
2712 return null;
2713 }
2714
2715 final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
Makoto Onuki55046222016-03-08 10:49:47 -08002716 if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
2717 return null;
2718 }
Makoto Onuki475c3652017-05-08 14:29:03 -07002719 final String path = mShortcutBitmapSaver.getBitmapPathMayWaitLocked(shortcutInfo);
2720 if (path == null) {
2721 Slog.w(TAG, "null bitmap detected in getShortcutIconFd()");
2722 return null;
2723 }
Makoto Onuki55046222016-03-08 10:49:47 -08002724 try {
2725 return ParcelFileDescriptor.open(
Makoto Onuki475c3652017-05-08 14:29:03 -07002726 new File(path),
Makoto Onuki55046222016-03-08 10:49:47 -08002727 ParcelFileDescriptor.MODE_READ_ONLY);
2728 } catch (FileNotFoundException e) {
Makoto Onuki475c3652017-05-08 14:29:03 -07002729 Slog.e(TAG, "Icon file not found: " + path);
Makoto Onuki55046222016-03-08 10:49:47 -08002730 return null;
2731 }
2732 }
2733 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002734
2735 @Override
Makoto Onukid99c6f02016-03-28 11:02:54 -07002736 public boolean hasShortcutHostPermission(int launcherUserId,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002737 @NonNull String callingPackage, int callingPid, int callingUid) {
2738 return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId,
2739 callingPid, callingUid);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002740 }
Sunny Goyal87a563e2017-01-01 19:42:45 -08002741
2742 @Override
Dianne Hackbornc160fa42017-11-01 16:14:26 -07002743 public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
2744 int userId) {
2745 ShortcutService.this.setShortcutHostPackage(type, packageName, userId);
2746 }
2747
2748 @Override
Sunny Goyal87a563e2017-01-01 19:42:45 -08002749 public boolean requestPinAppWidget(@NonNull String callingPackage,
Sunny Goyal4ad6b572017-02-28 11:11:51 -08002750 @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
2751 @Nullable IntentSender resultIntent, int userId) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08002752 Preconditions.checkNotNull(appWidget);
Sunny Goyal4ad6b572017-02-28 11:11:51 -08002753 return requestPinItem(callingPackage, userId, null, appWidget, extras, resultIntent);
Sunny Goyal87a563e2017-01-01 19:42:45 -08002754 }
Sunny Goyal7f7372a2017-01-24 11:53:54 -08002755
2756 @Override
2757 public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
2758 return ShortcutService.this.isRequestPinItemSupported(callingUserId, requestType);
2759 }
Tony Maked6ef622017-12-07 16:36:16 +00002760
2761 @Override
2762 public boolean isForegroundDefaultLauncher(@NonNull String callingPackage, int callingUid) {
2763 Preconditions.checkNotNull(callingPackage);
2764
2765 final int userId = UserHandle.getUserId(callingUid);
2766 final ComponentName defaultLauncher = getDefaultLauncher(userId);
2767 if (defaultLauncher == null) {
2768 return false;
2769 }
2770 if (!callingPackage.equals(defaultLauncher.getPackageName())) {
2771 return false;
2772 }
2773 synchronized (mLock) {
2774 if (!isUidForegroundLocked(callingUid)) {
2775 return false;
2776 }
2777 }
2778 return true;
2779 }
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002780 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002781
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002782 final BroadcastReceiver mReceiver = new BroadcastReceiver() {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002783 @Override
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002784 public void onReceive(Context context, Intent intent) {
2785 if (!mBootCompleted.get()) {
2786 return; // Boot not completed, ignore the broadcast.
2787 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07002788 try {
2789 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
2790 handleLocaleChanged();
2791 }
2792 } catch (Exception e) {
2793 wtf("Exception in mReceiver.onReceive", e);
Makoto Onukic51b2872016-05-04 15:24:50 -07002794 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002795 }
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002796 };
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002797
Makoto Onuki157b1622016-06-02 16:13:10 -07002798 void handleLocaleChanged() {
2799 if (DEBUG) {
2800 Slog.d(TAG, "handleLocaleChanged");
2801 }
2802 scheduleSaveBaseState();
2803
Makoto Onuki02f338e2016-07-29 09:40:40 -07002804 synchronized (mLock) {
2805 final long token = injectClearCallingIdentity();
2806 try {
2807 forEachLoadedUserLocked(user -> user.detectLocaleChange());
2808 } finally {
2809 injectRestoreCallingIdentity(token);
2810 }
Makoto Onuki157b1622016-06-02 16:13:10 -07002811 }
2812 }
2813
Makoto Onukif34c3082016-07-13 10:25:25 -07002814 /**
2815 * Package event callbacks.
2816 */
2817 @VisibleForTesting
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002818 final BroadcastReceiver mPackageMonitor = new BroadcastReceiver() {
Makoto Onukif34c3082016-07-13 10:25:25 -07002819 @Override
2820 public void onReceive(Context context, Intent intent) {
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002821 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
2822 if (userId == UserHandle.USER_NULL) {
2823 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
2824 return;
2825 }
2826
2827 final String action = intent.getAction();
2828
2829 // This is normally called on Handler, so clearCallingIdentity() isn't needed,
2830 // but we still check it in unit tests.
Makoto Onukif34c3082016-07-13 10:25:25 -07002831 final long token = injectClearCallingIdentity();
2832 try {
Makoto Onuki10305202016-07-14 18:14:08 -07002833 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002834 if (!isUserUnlockedL(userId)) {
2835 if (DEBUG) {
2836 Slog.d(TAG, "Ignoring package broadcast " + action
2837 + " for locked/stopped user " + userId);
2838 }
2839 return;
2840 }
2841
2842 // Whenever we get one of those package broadcasts, or get
2843 // ACTION_PREFERRED_ACTIVITY_CHANGED, we purge the default launcher cache.
Makoto Onuki10305202016-07-14 18:14:08 -07002844 final ShortcutUser user = getUserShortcutsLocked(userId);
2845 user.clearLauncher();
2846 }
2847 if (Intent.ACTION_PREFERRED_ACTIVITY_CHANGED.equals(action)) {
2848 // Nothing farther to do.
2849 return;
2850 }
2851
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002852 final Uri intentUri = intent.getData();
2853 final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart()
2854 : null;
2855 if (packageName == null) {
2856 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
2857 return;
2858 }
2859
2860 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
2861
2862 switch (action) {
2863 case Intent.ACTION_PACKAGE_ADDED:
2864 if (replacing) {
2865 handlePackageUpdateFinished(packageName, userId);
2866 } else {
2867 handlePackageAdded(packageName, userId);
2868 }
2869 break;
2870 case Intent.ACTION_PACKAGE_REMOVED:
2871 if (!replacing) {
2872 handlePackageRemoved(packageName, userId);
2873 }
2874 break;
2875 case Intent.ACTION_PACKAGE_CHANGED:
2876 handlePackageChanged(packageName, userId);
2877
2878 break;
2879 case Intent.ACTION_PACKAGE_DATA_CLEARED:
2880 handlePackageDataCleared(packageName, userId);
2881 break;
2882 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07002883 } catch (Exception e) {
2884 wtf("Exception in mPackageMonitor.onReceive", e);
Makoto Onukif34c3082016-07-13 10:25:25 -07002885 } finally {
2886 injectRestoreCallingIdentity(token);
Makoto Onukia2241832016-07-06 13:28:37 -07002887 }
Makoto Onukicdc78f72016-03-21 15:47:52 -07002888 }
Makoto Onukif34c3082016-07-13 10:25:25 -07002889 };
Makoto Onukicdc78f72016-03-21 15:47:52 -07002890
Makoto Onuki0acbb142016-03-22 17:02:57 -07002891 /**
Makoto Onuki39686e82016-04-13 18:03:00 -07002892 * Called when a user is unlocked.
2893 * - Check all known packages still exist, and otherwise perform cleanup.
2894 * - If a package still exists, check the version code. If it's been updated, may need to
Makoto Onukib08790c2016-06-23 14:05:46 -07002895 * update timestamps of its shortcuts.
Makoto Onuki0acbb142016-03-22 17:02:57 -07002896 */
Makoto Onukid99c6f02016-03-28 11:02:54 -07002897 @VisibleForTesting
Makoto Onuki39686e82016-04-13 18:03:00 -07002898 void checkPackageChanges(@UserIdInt int ownerUserId) {
Makoto Onukicdc78f72016-03-21 15:47:52 -07002899 if (DEBUG) {
Makoto Onuki39686e82016-04-13 18:03:00 -07002900 Slog.d(TAG, "checkPackageChanges() ownerUserId=" + ownerUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002901 }
Makoto Onukib08790c2016-06-23 14:05:46 -07002902 if (injectIsSafeModeEnabled()) {
2903 Slog.i(TAG, "Safe mode, skipping checkPackageChanges()");
2904 return;
2905 }
Makoto Onuki0acbb142016-03-22 17:02:57 -07002906
Makoto Onuki84d59342018-02-02 09:22:38 -08002907 final long start = getStatStartTime();
Makoto Onuki22fcc682016-05-17 14:52:19 -07002908 try {
2909 final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
Makoto Onuki9da23fc2016-03-29 11:14:42 -07002910
Makoto Onuki22fcc682016-05-17 14:52:19 -07002911 synchronized (mLock) {
2912 final ShortcutUser user = getUserShortcutsLocked(ownerUserId);
2913
2914 // Find packages that have been uninstalled.
2915 user.forAllPackageItems(spi -> {
2916 if (spi.getPackageInfo().isShadow()) {
2917 return; // Don't delete shadow information.
2918 }
2919 if (!isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07002920 if (DEBUG) {
2921 Slog.d(TAG, "Uninstalled: " + spi.getPackageName()
2922 + " user " + spi.getPackageUserId());
2923 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002924 gonePackages.add(PackageWithUser.of(spi));
2925 }
2926 });
2927 if (gonePackages.size() > 0) {
2928 for (int i = gonePackages.size() - 1; i >= 0; i--) {
2929 final PackageWithUser pu = gonePackages.get(i);
Makoto Onukib08790c2016-06-23 14:05:46 -07002930 cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId,
2931 /* appStillExists = */ false);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002932 }
Makoto Onukid99c6f02016-03-28 11:02:54 -07002933 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002934
Makoto Onuki248a0ef2016-11-03 15:59:01 -07002935 rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime());
Makoto Onuki0acbb142016-03-22 17:02:57 -07002936 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002937 } finally {
2938 logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start);
Makoto Onuki0acbb142016-03-22 17:02:57 -07002939 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07002940 verifyStates();
Makoto Onukicdc78f72016-03-21 15:47:52 -07002941 }
2942
Makoto Onuki248a0ef2016-11-03 15:59:01 -07002943 private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime) {
Makoto Onuki377b7972016-08-09 14:43:55 -07002944 final ShortcutUser user = getUserShortcutsLocked(userId);
2945
Makoto Onuki33663282016-08-22 16:19:04 -07002946 // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
2947 // is not reliable.
Makoto Onuki377b7972016-08-09 14:43:55 -07002948 final long now = injectCurrentTimeMillis();
Makoto Onuki33663282016-08-22 16:19:04 -07002949 final boolean afterOta =
2950 !injectBuildFingerprint().equals(user.getLastAppScanOsFingerprint());
Makoto Onuki377b7972016-08-09 14:43:55 -07002951
2952 // Then for each installed app, publish manifest shortcuts when needed.
Makoto Onuki33663282016-08-22 16:19:04 -07002953 forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
Makoto Onuki377b7972016-08-09 14:43:55 -07002954 user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
Makoto Onuki248a0ef2016-11-03 15:59:01 -07002955
2956 user.rescanPackageIfNeeded(ai.packageName, /* forceRescan= */ true);
Makoto Onuki377b7972016-08-09 14:43:55 -07002957 });
2958
2959 // Write the time just before the scan, because there may be apps that have just
2960 // been updated, and we want to catch them in the next time.
2961 user.setLastAppScanTime(now);
Makoto Onuki33663282016-08-22 16:19:04 -07002962 user.setLastAppScanOsFingerprint(injectBuildFingerprint());
Makoto Onuki377b7972016-08-09 14:43:55 -07002963 scheduleSaveUser(userId);
2964 }
2965
Makoto Onuki0acbb142016-03-22 17:02:57 -07002966 private void handlePackageAdded(String packageName, @UserIdInt int userId) {
Makoto Onukicdc78f72016-03-21 15:47:52 -07002967 if (DEBUG) {
Makoto Onuki0acbb142016-03-22 17:02:57 -07002968 Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
2969 }
2970 synchronized (mLock) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002971 final ShortcutUser user = getUserShortcutsLocked(userId);
2972 user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
Makoto Onuki64183d52016-08-08 14:11:34 -07002973 user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
Makoto Onuki0acbb142016-03-22 17:02:57 -07002974 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07002975 verifyStates();
Makoto Onuki0acbb142016-03-22 17:02:57 -07002976 }
2977
2978 private void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
Makoto Onuki905e8852016-03-28 10:40:58 -07002979 if (DEBUG) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07002980 Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d",
2981 packageName, userId));
Makoto Onuki0acbb142016-03-22 17:02:57 -07002982 }
2983 synchronized (mLock) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002984 final ShortcutUser user = getUserShortcutsLocked(userId);
2985 user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
Makoto Onuki39686e82016-04-13 18:03:00 -07002986
Makoto Onuki22fcc682016-05-17 14:52:19 -07002987 if (isPackageInstalled(packageName, userId)) {
Makoto Onuki64183d52016-08-08 14:11:34 -07002988 user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
Makoto Onuki39686e82016-04-13 18:03:00 -07002989 }
Makoto Onuki0acbb142016-03-22 17:02:57 -07002990 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07002991 verifyStates();
Makoto Onuki0acbb142016-03-22 17:02:57 -07002992 }
2993
Makoto Onuki2e210c42016-03-30 08:30:36 -07002994 private void handlePackageRemoved(String packageName, @UserIdInt int packageUserId) {
Makoto Onuki0acbb142016-03-22 17:02:57 -07002995 if (DEBUG) {
Makoto Onuki2e210c42016-03-30 08:30:36 -07002996 Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
2997 packageUserId));
Makoto Onukicdc78f72016-03-21 15:47:52 -07002998 }
Makoto Onukib08790c2016-06-23 14:05:46 -07002999 cleanUpPackageForAllLoadedUsers(packageName, packageUserId, /* appStillExists = */ false);
Makoto Onuki9e1f5592016-06-08 12:30:23 -07003000
3001 verifyStates();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07003002 }
3003
Makoto Onuki9ac59d02016-04-26 11:23:14 -07003004 private void handlePackageDataCleared(String packageName, int packageUserId) {
3005 if (DEBUG) {
3006 Slog.d(TAG, String.format("handlePackageDataCleared: %s user=%d", packageName,
3007 packageUserId));
Makoto Onukicdc78f72016-03-21 15:47:52 -07003008 }
Makoto Onukib08790c2016-06-23 14:05:46 -07003009 cleanUpPackageForAllLoadedUsers(packageName, packageUserId, /* appStillExists = */ true);
3010
3011 verifyStates();
3012 }
3013
3014 private void handlePackageChanged(String packageName, int packageUserId) {
Makoto Onuki82fb2eb2017-03-31 16:58:26 -07003015 if (!isPackageInstalled(packageName, packageUserId)) {
3016 // Probably disabled, which is the same thing as uninstalled.
3017 handlePackageRemoved(packageName, packageUserId);
3018 return;
3019 }
Makoto Onukib08790c2016-06-23 14:05:46 -07003020 if (DEBUG) {
3021 Slog.d(TAG, String.format("handlePackageChanged: %s user=%d", packageName,
3022 packageUserId));
3023 }
3024
3025 // Activities may be disabled or enabled. Just rescan the package.
3026 synchronized (mLock) {
3027 final ShortcutUser user = getUserShortcutsLocked(packageUserId);
3028
Makoto Onuki4e6cef42016-07-13 16:14:01 -07003029 user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
Makoto Onukib08790c2016-06-23 14:05:46 -07003030 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07003031
3032 verifyStates();
Makoto Onukicdc78f72016-03-21 15:47:52 -07003033 }
3034
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003035 // === PackageManager interaction ===
Makoto Onuki0acbb142016-03-22 17:02:57 -07003036
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003037 /**
3038 * Returns {@link PackageInfo} unless it's uninstalled or disabled.
3039 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003040 @Nullable
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003041 final PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) {
3042 return getPackageInfo(packageName, userId, true);
Makoto Onuki0acbb142016-03-22 17:02:57 -07003043 }
3044
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003045 /**
3046 * Returns {@link PackageInfo} unless it's uninstalled or disabled.
3047 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003048 @Nullable
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003049 final PackageInfo getPackageInfo(String packageName, @UserIdInt int userId) {
3050 return getPackageInfo(packageName, userId, false);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003051 }
3052
Makoto Onuki905e8852016-03-28 10:40:58 -07003053 int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003054 final long token = injectClearCallingIdentity();
Makoto Onuki905e8852016-03-28 10:40:58 -07003055 try {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003056 return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS, userId);
Makoto Onuki905e8852016-03-28 10:40:58 -07003057 } catch (RemoteException e) {
3058 // Shouldn't happen.
3059 Slog.wtf(TAG, "RemoteException", e);
3060 return -1;
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003061 } finally {
3062 injectRestoreCallingIdentity(token);
Makoto Onuki905e8852016-03-28 10:40:58 -07003063 }
Makoto Onuki0acbb142016-03-22 17:02:57 -07003064 }
3065
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003066 /**
3067 * Returns {@link PackageInfo} unless it's uninstalled or disabled.
3068 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003069 @Nullable
Makoto Onuki0acbb142016-03-22 17:02:57 -07003070 @VisibleForTesting
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003071 final PackageInfo getPackageInfo(String packageName, @UserIdInt int userId,
3072 boolean getSignatures) {
3073 return isInstalledOrNull(injectPackageInfoWithUninstalled(
3074 packageName, userId, getSignatures));
3075 }
3076
3077 /**
3078 * Do not use directly; this returns uninstalled packages too.
3079 */
3080 @Nullable
3081 @VisibleForTesting
3082 PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
Makoto Onuki0acbb142016-03-22 17:02:57 -07003083 boolean getSignatures) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003084 final long start = getStatStartTime();
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003085 final long token = injectClearCallingIdentity();
Makoto Onuki0acbb142016-03-22 17:02:57 -07003086 try {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003087 return mIPackageManager.getPackageInfo(
3088 packageName, PACKAGE_MATCH_FLAGS
3089 | (getSignatures ? PackageManager.GET_SIGNATURES : 0), userId);
Makoto Onuki0acbb142016-03-22 17:02:57 -07003090 } catch (RemoteException e) {
3091 // Shouldn't happen.
3092 Slog.wtf(TAG, "RemoteException", e);
3093 return null;
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003094 } finally {
3095 injectRestoreCallingIdentity(token);
Makoto Onuki2e210c42016-03-30 08:30:36 -07003096
3097 logDurationStat(
3098 (getSignatures ? Stats.GET_PACKAGE_INFO_WITH_SIG : Stats.GET_PACKAGE_INFO),
3099 start);
Makoto Onuki0acbb142016-03-22 17:02:57 -07003100 }
3101 }
3102
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003103 /**
3104 * Returns {@link ApplicationInfo} unless it's uninstalled or disabled.
3105 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003106 @Nullable
Makoto Onuki905e8852016-03-28 10:40:58 -07003107 @VisibleForTesting
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003108 final ApplicationInfo getApplicationInfo(String packageName, @UserIdInt int userId) {
3109 return isInstalledOrNull(injectApplicationInfoWithUninstalled(packageName, userId));
3110 }
3111
3112 /**
3113 * Do not use directly; this returns uninstalled packages too.
3114 */
3115 @Nullable
3116 @VisibleForTesting
3117 ApplicationInfo injectApplicationInfoWithUninstalled(
3118 String packageName, @UserIdInt int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003119 final long start = getStatStartTime();
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003120 final long token = injectClearCallingIdentity();
Makoto Onuki905e8852016-03-28 10:40:58 -07003121 try {
3122 return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
3123 } catch (RemoteException e) {
3124 // Shouldn't happen.
3125 Slog.wtf(TAG, "RemoteException", e);
3126 return null;
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003127 } finally {
3128 injectRestoreCallingIdentity(token);
Makoto Onuki2e210c42016-03-30 08:30:36 -07003129
3130 logDurationStat(Stats.GET_APPLICATION_INFO, start);
Makoto Onuki905e8852016-03-28 10:40:58 -07003131 }
3132 }
3133
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003134 /**
3135 * Returns {@link ActivityInfo} with its metadata unless it's uninstalled or disabled.
3136 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003137 @Nullable
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003138 final ActivityInfo getActivityInfoWithMetadata(ComponentName activity, @UserIdInt int userId) {
3139 return isInstalledOrNull(injectGetActivityInfoWithMetadataWithUninstalled(
3140 activity, userId));
3141 }
3142
3143 /**
3144 * Do not use directly; this returns uninstalled packages too.
3145 */
3146 @Nullable
3147 @VisibleForTesting
3148 ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(
3149 ComponentName activity, @UserIdInt int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003150 final long start = getStatStartTime();
Makoto Onuki22fcc682016-05-17 14:52:19 -07003151 final long token = injectClearCallingIdentity();
3152 try {
Makoto Onukib08790c2016-06-23 14:05:46 -07003153 return mIPackageManager.getActivityInfo(activity,
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003154 (PACKAGE_MATCH_FLAGS | PackageManager.GET_META_DATA), userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003155 } catch (RemoteException e) {
3156 // Shouldn't happen.
3157 Slog.wtf(TAG, "RemoteException", e);
3158 return null;
3159 } finally {
3160 injectRestoreCallingIdentity(token);
3161
Makoto Onukib08790c2016-06-23 14:05:46 -07003162 logDurationStat(Stats.GET_ACTIVITY_WITH_METADATA, start);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003163 }
3164 }
3165
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003166 /**
3167 * Return all installed and enabled packages.
3168 */
3169 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07003170 @VisibleForTesting
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003171 final List<PackageInfo> getInstalledPackages(@UserIdInt int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003172 final long start = getStatStartTime();
Makoto Onuki22fcc682016-05-17 14:52:19 -07003173 final long token = injectClearCallingIdentity();
3174 try {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003175 final List<PackageInfo> all = injectGetPackagesWithUninstalled(userId);
3176
3177 all.removeIf(PACKAGE_NOT_INSTALLED);
3178
3179 return all;
Makoto Onuki22fcc682016-05-17 14:52:19 -07003180 } catch (RemoteException e) {
3181 // Shouldn't happen.
3182 Slog.wtf(TAG, "RemoteException", e);
3183 return null;
3184 } finally {
3185 injectRestoreCallingIdentity(token);
3186
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003187 logDurationStat(Stats.GET_INSTALLED_PACKAGES, start);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003188 }
3189 }
3190
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003191 /**
3192 * Do not use directly; this returns uninstalled packages too.
3193 */
3194 @NonNull
3195 @VisibleForTesting
3196 List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId)
3197 throws RemoteException {
3198 final ParceledListSlice<PackageInfo> parceledList =
3199 mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId);
3200 if (parceledList == null) {
3201 return Collections.emptyList();
3202 }
3203 return parceledList.getList();
3204 }
3205
Makoto Onuki33663282016-08-22 16:19:04 -07003206 private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
Makoto Onuki22fcc682016-05-17 14:52:19 -07003207 Consumer<ApplicationInfo> callback) {
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003208 if (DEBUG) {
Makoto Onuki248a0ef2016-11-03 15:59:01 -07003209 Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime
3210 + " afterOta=" + afterOta);
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003211 }
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003212 final List<PackageInfo> list = getInstalledPackages(userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003213 for (int i = list.size() - 1; i >= 0; i--) {
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003214 final PackageInfo pi = list.get(i);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003215
Makoto Onuki64183d52016-08-08 14:11:34 -07003216 // If the package has been updated since the last scan time, then scan it.
Makoto Onuki248a0ef2016-11-03 15:59:01 -07003217 // Also if it's right after an OTA, always re-scan all apps anyway, since the
3218 // shortcut parser might have changed.
3219 if (afterOta || (pi.lastUpdateTime >= lastScanTime)) {
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003220 if (DEBUG) {
Makoto Onuki248a0ef2016-11-03 15:59:01 -07003221 Slog.d(TAG, "Found updated package " + pi.packageName
3222 + " updateTime=" + pi.lastUpdateTime);
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003223 }
3224 callback.accept(pi.applicationInfo);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003225 }
3226 }
3227 }
3228
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003229 private boolean isApplicationFlagSet(@NonNull String packageName, int userId, int flags) {
3230 final ApplicationInfo ai = injectApplicationInfoWithUninstalled(packageName, userId);
Makoto Onuki905e8852016-03-28 10:40:58 -07003231 return (ai != null) && ((ai.flags & flags) == flags);
3232 }
3233
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003234 private static boolean isInstalled(@Nullable ApplicationInfo ai) {
Makoto Onuki82fb2eb2017-03-31 16:58:26 -07003235 return (ai != null) && ai.enabled && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003236 }
3237
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08003238 private static boolean isEphemeralApp(@Nullable ApplicationInfo ai) {
Svetoslav Ganov096d3042017-01-30 16:34:13 -08003239 return (ai != null) && ai.isInstantApp();
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08003240 }
3241
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003242 private static boolean isInstalled(@Nullable PackageInfo pi) {
3243 return (pi != null) && isInstalled(pi.applicationInfo);
3244 }
3245
3246 private static boolean isInstalled(@Nullable ActivityInfo ai) {
3247 return (ai != null) && isInstalled(ai.applicationInfo);
3248 }
3249
3250 private static ApplicationInfo isInstalledOrNull(ApplicationInfo ai) {
3251 return isInstalled(ai) ? ai : null;
3252 }
3253
3254 private static PackageInfo isInstalledOrNull(PackageInfo pi) {
3255 return isInstalled(pi) ? pi : null;
3256 }
3257
3258 private static ActivityInfo isInstalledOrNull(ActivityInfo ai) {
3259 return isInstalled(ai) ? ai : null;
3260 }
3261
Makoto Onuki2e210c42016-03-30 08:30:36 -07003262 boolean isPackageInstalled(String packageName, int userId) {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003263 return getApplicationInfo(packageName, userId) != null;
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003264 }
3265
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08003266 boolean isEphemeralApp(String packageName, int userId) {
3267 return isEphemeralApp(getApplicationInfo(packageName, userId));
3268 }
3269
Makoto Onuki22fcc682016-05-17 14:52:19 -07003270 @Nullable
3271 XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07003272 return activityInfo.loadXmlMetaData(mContext.getPackageManager(), key);
Makoto Onuki39686e82016-04-13 18:03:00 -07003273 }
3274
Makoto Onuki157b1622016-06-02 16:13:10 -07003275 @Nullable
3276 Resources injectGetResourcesForApplicationAsUser(String packageName, int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003277 final long start = getStatStartTime();
Makoto Onuki157b1622016-06-02 16:13:10 -07003278 final long token = injectClearCallingIdentity();
3279 try {
3280 return mContext.getPackageManager().getResourcesForApplicationAsUser(
3281 packageName, userId);
3282 } catch (NameNotFoundException e) {
3283 Slog.e(TAG, "Resources for package " + packageName + " not found");
3284 return null;
3285 } finally {
3286 injectRestoreCallingIdentity(token);
3287
3288 logDurationStat(Stats.GET_APPLICATION_RESOURCES, start);
3289 }
3290 }
3291
Makoto Onukib08790c2016-06-23 14:05:46 -07003292 private Intent getMainActivityIntent() {
3293 final Intent intent = new Intent(Intent.ACTION_MAIN);
3294 intent.addCategory(LAUNCHER_INTENT_CATEGORY);
3295 return intent;
3296 }
3297
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003298 /**
3299 * Same as queryIntentActivitiesAsUser, except it makes sure the package is installed,
3300 * and only returns exported activities.
3301 */
3302 @NonNull
3303 @VisibleForTesting
3304 List<ResolveInfo> queryActivities(@NonNull Intent baseIntent,
3305 @NonNull String packageName, @Nullable ComponentName activity, int userId) {
3306
3307 baseIntent.setPackage(Preconditions.checkNotNull(packageName));
3308 if (activity != null) {
3309 baseIntent.setComponent(activity);
3310 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08003311 return queryActivities(baseIntent, userId, /* exportedOnly =*/ true);
3312 }
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003313
Makoto Onuki2d895c32016-12-02 15:48:40 -08003314 @NonNull
3315 List<ResolveInfo> queryActivities(@NonNull Intent intent, int userId,
3316 boolean exportedOnly) {
3317 final List<ResolveInfo> resolved;
3318 final long token = injectClearCallingIdentity();
3319 try {
3320 resolved =
3321 mContext.getPackageManager().queryIntentActivitiesAsUser(
3322 intent, PACKAGE_MATCH_FLAGS, userId);
3323 } finally {
3324 injectRestoreCallingIdentity(token);
3325 }
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003326 if (resolved == null || resolved.size() == 0) {
3327 return EMPTY_RESOLVE_INFO;
3328 }
3329 // Make sure the package is installed.
3330 if (!isInstalled(resolved.get(0).activityInfo)) {
3331 return EMPTY_RESOLVE_INFO;
3332 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08003333 if (exportedOnly) {
3334 resolved.removeIf(ACTIVITY_NOT_EXPORTED);
3335 }
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003336 return resolved;
3337 }
3338
3339 /**
3340 * Return the main activity that is enabled and exported. If multiple activities are found,
3341 * return the first one.
3342 */
Makoto Onukib08790c2016-06-23 14:05:46 -07003343 @Nullable
3344 ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003345 final long start = getStatStartTime();
Makoto Onukib08790c2016-06-23 14:05:46 -07003346 try {
Makoto Onukib08790c2016-06-23 14:05:46 -07003347 final List<ResolveInfo> resolved =
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003348 queryActivities(getMainActivityIntent(), packageName, null, userId);
3349 return resolved.size() == 0 ? null : resolved.get(0).activityInfo.getComponentName();
Makoto Onukib08790c2016-06-23 14:05:46 -07003350 } finally {
Makoto Onukib08790c2016-06-23 14:05:46 -07003351 logDurationStat(Stats.GET_LAUNCHER_ACTIVITY, start);
3352 }
3353 }
3354
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003355 /**
3356 * Return whether an activity is enabled, exported and main.
3357 */
Makoto Onukib08790c2016-06-23 14:05:46 -07003358 boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003359 final long start = getStatStartTime();
Makoto Onukib08790c2016-06-23 14:05:46 -07003360 try {
Makoto Onuki34145532017-03-14 17:58:36 -07003361 if (activity == null) {
3362 wtf("null activity detected");
3363 return false;
3364 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08003365 if (DUMMY_MAIN_ACTIVITY.equals(activity.getClassName())) {
3366 return true;
3367 }
3368 final List<ResolveInfo> resolved = queryActivities(
3369 getMainActivityIntent(), activity.getPackageName(), activity, userId);
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003370 return resolved.size() > 0;
Makoto Onukib08790c2016-06-23 14:05:46 -07003371 } finally {
Makoto Onukib08790c2016-06-23 14:05:46 -07003372 logDurationStat(Stats.CHECK_LAUNCHER_ACTIVITY, start);
3373 }
3374 }
3375
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003376 /**
Makoto Onuki2d895c32016-12-02 15:48:40 -08003377 * Create a dummy "main activity" component name which is used to create a dynamic shortcut
3378 * with no main activity temporarily.
3379 */
3380 @NonNull
3381 ComponentName getDummyMainActivity(@NonNull String packageName) {
3382 return new ComponentName(packageName, DUMMY_MAIN_ACTIVITY);
3383 }
3384
Makoto Onuki255461f2017-01-10 11:47:25 -08003385 boolean isDummyMainActivity(@Nullable ComponentName name) {
3386 return name != null && DUMMY_MAIN_ACTIVITY.equals(name.getClassName());
3387 }
3388
Makoto Onuki2d895c32016-12-02 15:48:40 -08003389 /**
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003390 * Return all the enabled, exported and main activities from a package.
3391 */
Makoto Onukib08790c2016-06-23 14:05:46 -07003392 @NonNull
3393 List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003394 final long start = getStatStartTime();
Makoto Onukib08790c2016-06-23 14:05:46 -07003395 try {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003396 return queryActivities(getMainActivityIntent(), packageName, null, userId);
Makoto Onukib08790c2016-06-23 14:05:46 -07003397 } finally {
Makoto Onukib08790c2016-06-23 14:05:46 -07003398 logDurationStat(Stats.CHECK_LAUNCHER_ACTIVITY, start);
3399 }
3400 }
3401
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003402 /**
3403 * Return whether an activity is enabled and exported.
3404 */
3405 @VisibleForTesting
3406 boolean injectIsActivityEnabledAndExported(
3407 @NonNull ComponentName activity, @UserIdInt int userId) {
Makoto Onuki84d59342018-02-02 09:22:38 -08003408 final long start = getStatStartTime();
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003409 try {
3410 return queryActivities(new Intent(), activity.getPackageName(), activity, userId)
3411 .size() > 0;
3412 } finally {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003413 logDurationStat(Stats.IS_ACTIVITY_ENABLED, start);
3414 }
3415 }
3416
Makoto Onuki2d895c32016-12-02 15:48:40 -08003417 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -08003418 * Get the {@link LauncherApps#ACTION_CONFIRM_PIN_SHORTCUT} or
3419 * {@link LauncherApps#ACTION_CONFIRM_PIN_APPWIDGET} activity in a given package depending on
3420 * the requestType.
Makoto Onuki2d895c32016-12-02 15:48:40 -08003421 */
3422 @Nullable
3423 ComponentName injectGetPinConfirmationActivity(@NonNull String launcherPackageName,
Sunny Goyal7f7372a2017-01-24 11:53:54 -08003424 int launcherUserId, int requestType) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08003425 Preconditions.checkNotNull(launcherPackageName);
Sunny Goyal7f7372a2017-01-24 11:53:54 -08003426 String action = requestType == LauncherApps.PinItemRequest.REQUEST_TYPE_SHORTCUT ?
3427 LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT :
3428 LauncherApps.ACTION_CONFIRM_PIN_APPWIDGET;
Makoto Onuki2d895c32016-12-02 15:48:40 -08003429
Sunny Goyal7f7372a2017-01-24 11:53:54 -08003430 final Intent confirmIntent = new Intent(action).setPackage(launcherPackageName);
Makoto Onuki2d895c32016-12-02 15:48:40 -08003431 final List<ResolveInfo> candidates = queryActivities(
3432 confirmIntent, launcherUserId, /* exportedOnly =*/ false);
3433 for (ResolveInfo ri : candidates) {
3434 return ri.activityInfo.getComponentName();
3435 }
3436 return null;
3437 }
3438
Makoto Onukib08790c2016-06-23 14:05:46 -07003439 boolean injectIsSafeModeEnabled() {
3440 final long token = injectClearCallingIdentity();
3441 try {
3442 return IWindowManager.Stub
3443 .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE))
3444 .isSafeModeEnabled();
3445 } catch (RemoteException e) {
3446 return false; // Shouldn't happen though.
3447 } finally {
3448 injectRestoreCallingIdentity(token);
3449 }
3450 }
3451
Makoto Onuki2d895c32016-12-02 15:48:40 -08003452 /**
3453 * If {@code userId} is of a managed profile, return the parent user ID. Otherwise return
3454 * itself.
3455 */
3456 int getParentOrSelfUserId(int userId) {
3457 final long token = injectClearCallingIdentity();
3458 try {
3459 final UserInfo parent = mUserManager.getProfileParent(userId);
3460 return (parent != null) ? parent.id : userId;
3461 } finally {
3462 injectRestoreCallingIdentity(token);
3463 }
3464 }
3465
Sunny Goyal87a563e2017-01-01 19:42:45 -08003466 void injectSendIntentSender(IntentSender intentSender, Intent extras) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08003467 if (intentSender == null) {
3468 return;
3469 }
3470 try {
Sunny Goyal87a563e2017-01-01 19:42:45 -08003471 intentSender.sendIntent(mContext, /* code= */ 0, extras,
Makoto Onuki2d895c32016-12-02 15:48:40 -08003472 /* onFinished=*/ null, /* handler= */ null);
3473 } catch (SendIntentException e) {
3474 Slog.w(TAG, "sendIntent failed().", e);
3475 }
3476 }
3477
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003478 // === Backup & restore ===
3479
Makoto Onuki0acbb142016-03-22 17:02:57 -07003480 boolean shouldBackupApp(String packageName, int userId) {
Makoto Onuki905e8852016-03-28 10:40:58 -07003481 return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
Makoto Onuki0acbb142016-03-22 17:02:57 -07003482 }
3483
Makoto Onukia4f89b12017-10-05 10:37:55 -07003484 static boolean shouldBackupApp(PackageInfo pi) {
Makoto Onuki2e210c42016-03-30 08:30:36 -07003485 return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
3486 }
3487
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003488 @Override
Makoto Onuki2e210c42016-03-30 08:30:36 -07003489 public byte[] getBackupPayload(@UserIdInt int userId) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003490 enforceSystem();
3491 if (DEBUG) {
3492 Slog.d(TAG, "Backing up user " + userId);
3493 }
3494 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07003495 if (!isUserUnlockedL(userId)) {
3496 wtf("Can't backup: user " + userId + " is locked or not running");
3497 return null;
3498 }
3499
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003500 final ShortcutUser user = getUserShortcutsLocked(userId);
3501 if (user == null) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07003502 wtf("Can't backup: user not found: id=" + userId);
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003503 return null;
3504 }
3505
Makoto Onukic8c33292016-09-12 16:36:59 -07003506 // Update the signatures for all packages.
3507 user.forAllPackageItems(spi -> spi.refreshPackageSignatureAndSave());
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003508
Makoto Onukic8c33292016-09-12 16:36:59 -07003509 // Set the version code for the launchers.
3510 // We shouldn't do this for publisher packages, because we don't want to update the
3511 // version code without rescanning the manifest.
Makoto Onukia4f89b12017-10-05 10:37:55 -07003512 user.forAllLaunchers(launcher -> launcher.ensurePackageInfo());
Makoto Onukic8c33292016-09-12 16:36:59 -07003513
3514 // Save to the filesystem.
3515 scheduleSaveUser(userId);
3516 saveDirtyInfo();
3517
Makoto Onuki475c3652017-05-08 14:29:03 -07003518 // Note, in case of backup, we don't have to wait on bitmap saving, because we don't
3519 // back up bitmaps anyway.
3520
Makoto Onukic8c33292016-09-12 16:36:59 -07003521 // Then create the backup payload.
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003522 final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
3523 try {
3524 saveUserInternalLocked(userId, os, /* forBackup */ true);
Makoto Onukib08790c2016-06-23 14:05:46 -07003525 } catch (XmlPullParserException | IOException e) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003526 // Shouldn't happen.
3527 Slog.w(TAG, "Backup failed.", e);
3528 return null;
3529 }
3530 return os.toByteArray();
3531 }
3532 }
3533
3534 @Override
Makoto Onuki2e210c42016-03-30 08:30:36 -07003535 public void applyRestore(byte[] payload, @UserIdInt int userId) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003536 enforceSystem();
3537 if (DEBUG) {
3538 Slog.d(TAG, "Restoring user " + userId);
3539 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003540 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07003541 if (!isUserUnlockedL(userId)) {
3542 wtf("Can't restore: user " + userId + " is locked or not running");
3543 return;
3544 }
Makoto Onuki50a320e2017-05-31 14:38:42 -07003545
3546 // Note we print the file timestamps in dumpsys too, but also printing the timestamp
3547 // in the files anyway.
3548 mShortcutDumpFiles.save("restore-0-start.txt", pw -> {
3549 pw.print("Start time: ");
3550 dumpCurrentTime(pw);
3551 pw.println();
3552 });
3553 mShortcutDumpFiles.save("restore-1-payload.xml", payload);
3554
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07003555 // Actually do restore.
3556 final ShortcutUser restored;
Makoto Onuki02f338e2016-07-29 09:40:40 -07003557 final ByteArrayInputStream is = new ByteArrayInputStream(payload);
3558 try {
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07003559 restored = loadUserInternal(userId, is, /* fromBackup */ true);
3560 } catch (XmlPullParserException | IOException | InvalidFileFormatException e) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07003561 Slog.w(TAG, "Restoration failed.", e);
3562 return;
3563 }
Makoto Onuki50a320e2017-05-31 14:38:42 -07003564 mShortcutDumpFiles.save("restore-2.txt", this::dumpInner);
3565
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07003566 getUserShortcutsLocked(userId).mergeRestoredFile(restored);
Makoto Onuki2e210c42016-03-30 08:30:36 -07003567
Makoto Onuki50a320e2017-05-31 14:38:42 -07003568 mShortcutDumpFiles.save("restore-3.txt", this::dumpInner);
3569
Makoto Onuki377b7972016-08-09 14:43:55 -07003570 // Rescan all packages to re-publish manifest shortcuts and do other checks.
3571 rescanUpdatedPackagesLocked(userId,
Makoto Onuki248a0ef2016-11-03 15:59:01 -07003572 0 // lastScanTime = 0; rescan all packages.
3573 );
Makoto Onuki2e210c42016-03-30 08:30:36 -07003574
Makoto Onuki50a320e2017-05-31 14:38:42 -07003575 mShortcutDumpFiles.save("restore-4.txt", this::dumpInner);
3576
3577 mShortcutDumpFiles.save("restore-5-finish.txt", pw -> {
3578 pw.print("Finish time: ");
3579 dumpCurrentTime(pw);
3580 pw.println();
3581 });
3582
Makoto Onuki2e210c42016-03-30 08:30:36 -07003583 saveUserLocked(userId);
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003584 }
Makoto Onukicdc78f72016-03-21 15:47:52 -07003585 }
3586
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003587 // === Dump ===
3588
3589 @Override
3590 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003591 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Makoto Onukic4361e32017-04-03 11:24:25 -07003592 dumpNoCheck(fd, pw, args);
3593 }
3594
3595 @VisibleForTesting
3596 void dumpNoCheck(FileDescriptor fd, PrintWriter pw, String[] args) {
Makoto Onuki20b82212017-10-04 15:03:50 -07003597 final DumpFilter filter = parseDumpArgs(args);
Makoto Onuki50a320e2017-05-31 14:38:42 -07003598
Makoto Onuki20b82212017-10-04 15:03:50 -07003599 if (filter.shouldDumpCheckIn()) {
Makoto Onuki50a320e2017-05-31 14:38:42 -07003600 // Other flags are not supported for checkin.
Makoto Onuki20b82212017-10-04 15:03:50 -07003601 dumpCheckin(pw, filter.shouldCheckInClear());
Makoto Onuki76269922016-07-15 14:58:54 -07003602 } else {
Makoto Onuki20b82212017-10-04 15:03:50 -07003603 if (filter.shouldDumpMain()) {
3604 dumpInner(pw, filter);
Makoto Onuki50a320e2017-05-31 14:38:42 -07003605 pw.println();
3606 }
Makoto Onuki20b82212017-10-04 15:03:50 -07003607 if (filter.shouldDumpUid()) {
Makoto Onuki50a320e2017-05-31 14:38:42 -07003608 dumpUid(pw);
3609 pw.println();
3610 }
Makoto Onuki20b82212017-10-04 15:03:50 -07003611 if (filter.shouldDumpFiles()) {
Makoto Onuki50a320e2017-05-31 14:38:42 -07003612 dumpDumpFiles(pw);
3613 pw.println();
3614 }
Makoto Onuki76269922016-07-15 14:58:54 -07003615 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003616 }
3617
Makoto Onuki20b82212017-10-04 15:03:50 -07003618 private static DumpFilter parseDumpArgs(String[] args) {
3619 final DumpFilter filter = new DumpFilter();
3620 if (args == null) {
3621 return filter;
3622 }
Makoto Onuki55046222016-03-08 10:49:47 -08003623
Makoto Onuki20b82212017-10-04 15:03:50 -07003624 int argIndex = 0;
3625 while (argIndex < args.length) {
3626 final String arg = args[argIndex++];
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003627
Makoto Onuki20b82212017-10-04 15:03:50 -07003628 if ("-c".equals(arg)) {
3629 filter.setDumpCheckIn(true);
3630 continue;
3631 }
3632 if ("--checkin".equals(arg)) {
3633 filter.setDumpCheckIn(true);
3634 filter.setCheckInClear(true);
3635 continue;
3636 }
3637 if ("-a".equals(arg) || "--all".equals(arg)) {
3638 filter.setDumpUid(true);
3639 filter.setDumpFiles(true);
3640 continue;
3641 }
3642 if ("-u".equals(arg) || "--uid".equals(arg)) {
3643 filter.setDumpUid(true);
3644 continue;
3645 }
3646 if ("-f".equals(arg) || "--files".equals(arg)) {
3647 filter.setDumpFiles(true);
3648 continue;
3649 }
3650 if ("-n".equals(arg) || "--no-main".equals(arg)) {
3651 filter.setDumpMain(false);
3652 continue;
3653 }
3654 if ("--user".equals(arg)) {
3655 if (argIndex >= args.length) {
3656 throw new IllegalArgumentException("Missing user ID for --user");
3657 }
3658 try {
3659 filter.addUser(Integer.parseInt(args[argIndex++]));
3660 } catch (NumberFormatException e) {
3661 throw new IllegalArgumentException("Invalid user ID", e);
3662 }
3663 continue;
3664 }
3665 if ("-p".equals(arg) || "--package".equals(arg)) {
3666 if (argIndex >= args.length) {
3667 throw new IllegalArgumentException("Missing package name for --package");
3668 }
3669 filter.addPackageRegex(args[argIndex++]);
3670 filter.setDumpDetails(false);
3671 continue;
3672 }
3673 if (arg.startsWith("-")) {
3674 throw new IllegalArgumentException("Unknown option " + arg);
3675 }
3676 break;
3677 }
3678 while (argIndex < args.length) {
3679 filter.addPackage(args[argIndex++]);
3680 }
3681 return filter;
3682 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003683
Makoto Onuki20b82212017-10-04 15:03:50 -07003684 static class DumpFilter {
3685 private boolean mDumpCheckIn = false;
3686 private boolean mCheckInClear = false;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07003687
Makoto Onuki20b82212017-10-04 15:03:50 -07003688 private boolean mDumpMain = true;
3689 private boolean mDumpUid = false;
3690 private boolean mDumpFiles = false;
Makoto Onuki55046222016-03-08 10:49:47 -08003691
Makoto Onuki20b82212017-10-04 15:03:50 -07003692 private boolean mDumpDetails = true;
3693 private List<Pattern> mPackagePatterns = new ArrayList<>();
3694 private List<Integer> mUsers = new ArrayList<>();
3695
3696 void addPackageRegex(String regex) {
3697 mPackagePatterns.add(Pattern.compile(regex));
3698 }
3699
3700 public void addPackage(String packageName) {
3701 addPackageRegex(Pattern.quote(packageName));
3702 }
3703
3704 void addUser(int userId) {
3705 mUsers.add(userId);
3706 }
3707
3708 boolean isPackageMatch(String packageName) {
3709 if (mPackagePatterns.size() == 0) {
3710 return true;
3711 }
3712 for (int i = 0; i < mPackagePatterns.size(); i++) {
3713 if (mPackagePatterns.get(i).matcher(packageName).find()) {
3714 return true;
Makoto Onuki085a05c2016-08-19 11:39:29 -07003715 }
Makoto Onuki2e210c42016-03-30 08:30:36 -07003716 }
Makoto Onuki20b82212017-10-04 15:03:50 -07003717 return false;
3718 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003719
Makoto Onuki20b82212017-10-04 15:03:50 -07003720 boolean isUserMatch(int userId) {
3721 if (mUsers.size() == 0) {
3722 return true;
3723 }
3724 for (int i = 0; i < mUsers.size(); i++) {
3725 if (mUsers.get(i) == userId) {
3726 return true;
3727 }
3728 }
3729 return false;
3730 }
Makoto Onukia2241832016-07-06 13:28:37 -07003731
Makoto Onuki20b82212017-10-04 15:03:50 -07003732 public boolean shouldDumpCheckIn() {
3733 return mDumpCheckIn;
3734 }
3735
3736 public void setDumpCheckIn(boolean dumpCheckIn) {
3737 mDumpCheckIn = dumpCheckIn;
3738 }
3739
3740 public boolean shouldCheckInClear() {
3741 return mCheckInClear;
3742 }
3743
3744 public void setCheckInClear(boolean checkInClear) {
3745 mCheckInClear = checkInClear;
3746 }
3747
3748 public boolean shouldDumpMain() {
3749 return mDumpMain;
3750 }
3751
3752 public void setDumpMain(boolean dumpMain) {
3753 mDumpMain = dumpMain;
3754 }
3755
3756 public boolean shouldDumpUid() {
3757 return mDumpUid;
3758 }
3759
3760 public void setDumpUid(boolean dumpUid) {
3761 mDumpUid = dumpUid;
3762 }
3763
3764 public boolean shouldDumpFiles() {
3765 return mDumpFiles;
3766 }
3767
3768 public void setDumpFiles(boolean dumpFiles) {
3769 mDumpFiles = dumpFiles;
3770 }
3771
3772 public boolean shouldDumpDetails() {
3773 return mDumpDetails;
3774 }
3775
3776 public void setDumpDetails(boolean dumpDetails) {
3777 mDumpDetails = dumpDetails;
3778 }
3779 }
3780
3781 private void dumpInner(PrintWriter pw) {
3782 dumpInner(pw, new DumpFilter());
3783 }
3784
3785 private void dumpInner(PrintWriter pw, DumpFilter filter) {
3786 synchronized (mLock) {
3787 if (filter.shouldDumpDetails()) {
3788 final long now = injectCurrentTimeMillis();
3789 pw.print("Now: [");
3790 pw.print(now);
3791 pw.print("] ");
3792 pw.print(formatTime(now));
3793
3794 pw.print(" Raw last reset: [");
3795 pw.print(mRawLastResetTime);
3796 pw.print("] ");
3797 pw.print(formatTime(mRawLastResetTime));
3798
3799 final long last = getLastResetTimeLocked();
3800 pw.print(" Last reset: [");
3801 pw.print(last);
3802 pw.print("] ");
3803 pw.print(formatTime(last));
3804
3805 final long next = getNextResetTimeLocked();
3806 pw.print(" Next reset: [");
3807 pw.print(next);
3808 pw.print("] ");
3809 pw.print(formatTime(next));
3810
3811 pw.print(" Config:");
3812 pw.print(" Max icon dim: ");
3813 pw.println(mMaxIconDimension);
3814 pw.print(" Icon format: ");
3815 pw.println(mIconPersistFormat);
3816 pw.print(" Icon quality: ");
3817 pw.println(mIconPersistQuality);
3818 pw.print(" saveDelayMillis: ");
3819 pw.println(mSaveDelayMillis);
3820 pw.print(" resetInterval: ");
3821 pw.println(mResetInterval);
3822 pw.print(" maxUpdatesPerInterval: ");
3823 pw.println(mMaxUpdatesPerInterval);
3824 pw.print(" maxShortcutsPerActivity: ");
3825 pw.println(mMaxShortcuts);
3826 pw.println();
3827
Makoto Onuki84d59342018-02-02 09:22:38 -08003828 mStatLogger.dump(pw, " ");
Makoto Onuki20b82212017-10-04 15:03:50 -07003829
3830 pw.println();
3831 pw.print(" #Failures: ");
3832 pw.println(mWtfCount);
3833
3834 if (mLastWtfStacktrace != null) {
3835 pw.print(" Last failure stack trace: ");
3836 pw.println(Log.getStackTraceString(mLastWtfStacktrace));
3837 }
3838
3839 pw.println();
3840 mShortcutBitmapSaver.dumpLocked(pw, " ");
3841
3842 pw.println();
Makoto Onukia2241832016-07-06 13:28:37 -07003843 }
3844
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -08003845 for (int i = 0; i < mUsers.size(); i++) {
Makoto Onuki20b82212017-10-04 15:03:50 -07003846 final ShortcutUser user = mUsers.valueAt(i);
3847 if (filter.isUserMatch(user.getUserId())) {
3848 user.dump(pw, " ", filter);
3849 pw.println();
3850 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003851 }
Makoto Onuki708703b2017-12-11 16:38:11 -08003852
3853 for (int i = 0; i < mShortcutNonPersistentUsers.size(); i++) {
3854 final ShortcutNonPersistentUser user = mShortcutNonPersistentUsers.valueAt(i);
3855 if (filter.isUserMatch(user.getUserId())) {
3856 user.dump(pw, " ", filter);
3857 pw.println();
3858 }
3859 }
Makoto Onuki50a320e2017-05-31 14:38:42 -07003860 }
3861 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07003862
Makoto Onuki50a320e2017-05-31 14:38:42 -07003863 private void dumpUid(PrintWriter pw) {
3864 synchronized (mLock) {
3865 pw.println("** SHORTCUT MANAGER UID STATES (dumpsys shortcut -n -u)");
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07003866
3867 for (int i = 0; i < mUidState.size(); i++) {
3868 final int uid = mUidState.keyAt(i);
3869 final int state = mUidState.valueAt(i);
3870 pw.print(" UID=");
3871 pw.print(uid);
3872 pw.print(" state=");
3873 pw.print(state);
3874 if (isProcessStateForeground(state)) {
3875 pw.print(" [FG]");
3876 }
3877 pw.print(" last FG=");
3878 pw.print(mUidLastForegroundElapsedTime.get(uid));
3879 pw.println();
3880 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003881 }
3882 }
3883
Makoto Onuki41066a62016-03-09 16:18:44 -08003884 static String formatTime(long time) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003885 Time tobj = new Time();
3886 tobj.set(time);
3887 return tobj.format("%Y-%m-%d %H:%M:%S");
3888 }
3889
Makoto Onuki50a320e2017-05-31 14:38:42 -07003890 private void dumpCurrentTime(PrintWriter pw) {
3891 pw.print(formatTime(injectCurrentTimeMillis()));
3892 }
3893
Makoto Onuki76269922016-07-15 14:58:54 -07003894 /**
3895 * Dumpsys for checkin.
3896 *
3897 * @param clear if true, clear the history information. Some other system services have this
3898 * behavior but shortcut service doesn't for now.
3899 */
3900 private void dumpCheckin(PrintWriter pw, boolean clear) {
3901 synchronized (mLock) {
3902 try {
3903 final JSONArray users = new JSONArray();
3904
3905 for (int i = 0; i < mUsers.size(); i++) {
3906 users.put(mUsers.valueAt(i).dumpCheckin(clear));
3907 }
3908
3909 final JSONObject result = new JSONObject();
3910
3911 result.put(KEY_SHORTCUT, users);
3912 result.put(KEY_LOW_RAM, injectIsLowRamDevice());
3913 result.put(KEY_ICON_SIZE, mMaxIconDimension);
3914
3915 pw.println(result.toString(1));
3916 } catch (JSONException e) {
3917 Slog.e(TAG, "Unable to write in json", e);
3918 }
3919 }
3920 }
3921
Makoto Onuki50a320e2017-05-31 14:38:42 -07003922 private void dumpDumpFiles(PrintWriter pw) {
3923 synchronized (mLock) {
3924 pw.println("** SHORTCUT MANAGER FILES (dumpsys shortcut -n -f)");
3925 mShortcutDumpFiles.dumpAll(pw);
3926 }
3927 }
3928
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003929 // === Shell support ===
3930
3931 @Override
3932 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
Dianne Hackborn354736e2016-08-22 17:00:05 -07003933 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003934
3935 enforceShell();
3936
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07003937 final long token = injectClearCallingIdentity();
3938 try {
Dianne Hackborn354736e2016-08-22 17:00:05 -07003939 final int status = (new MyShellCommand()).exec(this, in, out, err, args, callback,
3940 resultReceiver);
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07003941 resultReceiver.send(status, null);
3942 } finally {
3943 injectRestoreCallingIdentity(token);
3944 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003945 }
3946
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003947 static class CommandException extends Exception {
3948 public CommandException(String message) {
3949 super(message);
3950 }
3951 }
3952
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003953 /**
3954 * Handle "adb shell cmd".
3955 */
3956 private class MyShellCommand extends ShellCommand {
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003957
3958 private int mUserId = UserHandle.USER_SYSTEM;
3959
Makoto Onuki02f338e2016-07-29 09:40:40 -07003960 private void parseOptionsLocked(boolean takeUser)
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003961 throws CommandException {
3962 String opt;
3963 while ((opt = getNextOption()) != null) {
3964 switch (opt) {
3965 case "--user":
3966 if (takeUser) {
3967 mUserId = UserHandle.parseUserArg(getNextArgRequired());
Makoto Onuki02f338e2016-07-29 09:40:40 -07003968 if (!isUserUnlockedL(mUserId)) {
Makoto Onukif34c3082016-07-13 10:25:25 -07003969 throw new CommandException(
3970 "User " + mUserId + " is not running or locked");
3971 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003972 break;
3973 }
3974 // fallthrough
3975 default:
3976 throw new CommandException("Unknown option: " + opt);
3977 }
3978 }
3979 }
3980
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003981 @Override
3982 public int onCommand(String cmd) {
3983 if (cmd == null) {
3984 return handleDefaultCommands(cmd);
3985 }
3986 final PrintWriter pw = getOutPrintWriter();
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003987 try {
3988 switch (cmd) {
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003989 case "reset-throttling":
3990 handleResetThrottling();
3991 break;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07003992 case "reset-all-throttling":
3993 handleResetAllThrottling();
3994 break;
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003995 case "override-config":
3996 handleOverrideConfig();
3997 break;
3998 case "reset-config":
3999 handleResetConfig();
4000 break;
4001 case "clear-default-launcher":
4002 handleClearDefaultLauncher();
4003 break;
4004 case "get-default-launcher":
4005 handleGetDefaultLauncher();
4006 break;
Makoto Onukiac214972016-04-04 10:19:45 -07004007 case "unload-user":
4008 handleUnloadUser();
4009 break;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004010 case "clear-shortcuts":
4011 handleClearShortcuts();
4012 break;
Makoto Onukib08790c2016-06-23 14:05:46 -07004013 case "verify-states": // hidden command to verify various internal states.
4014 handleVerifyStates();
4015 break;
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004016 default:
4017 return handleDefaultCommands(cmd);
4018 }
4019 } catch (CommandException e) {
4020 pw.println("Error: " + e.getMessage());
4021 return 1;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004022 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004023 pw.println("Success");
4024 return 0;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004025 }
4026
4027 @Override
4028 public void onHelp() {
4029 final PrintWriter pw = getOutPrintWriter();
4030 pw.println("Usage: cmd shortcut COMMAND [options ...]");
4031 pw.println();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004032 pw.println("cmd shortcut reset-throttling [--user USER_ID]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004033 pw.println(" Reset throttling for all packages and users");
4034 pw.println();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004035 pw.println("cmd shortcut reset-all-throttling");
4036 pw.println(" Reset the throttling state for all users");
4037 pw.println();
Makoto Onuki4362a662016-03-08 18:59:09 -08004038 pw.println("cmd shortcut override-config CONFIG");
4039 pw.println(" Override the configuration for testing (will last until reboot)");
4040 pw.println();
4041 pw.println("cmd shortcut reset-config");
4042 pw.println(" Reset the configuration set with \"update-config\"");
4043 pw.println();
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004044 pw.println("cmd shortcut clear-default-launcher [--user USER_ID]");
4045 pw.println(" Clear the cached default launcher");
4046 pw.println();
4047 pw.println("cmd shortcut get-default-launcher [--user USER_ID]");
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07004048 pw.println(" Show the default launcher");
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004049 pw.println();
Makoto Onukiac214972016-04-04 10:19:45 -07004050 pw.println("cmd shortcut unload-user [--user USER_ID]");
4051 pw.println(" Unload a user from the memory");
4052 pw.println(" (This should not affect any observable behavior)");
4053 pw.println();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004054 pw.println("cmd shortcut clear-shortcuts [--user USER_ID] PACKAGE");
4055 pw.println(" Remove all shortcuts from a package, including pinned shortcuts");
4056 pw.println();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004057 }
4058
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004059 private void handleResetThrottling() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004060 synchronized (mLock) {
4061 parseOptionsLocked(/* takeUser =*/ true);
Makoto Onuki4554d0e2016-03-14 15:51:41 -07004062
Makoto Onuki02f338e2016-07-29 09:40:40 -07004063 Slog.i(TAG, "cmd: handleResetThrottling: user=" + mUserId);
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004064
Makoto Onuki02f338e2016-07-29 09:40:40 -07004065 resetThrottlingInner(mUserId);
4066 }
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004067 }
4068
4069 private void handleResetAllThrottling() {
4070 Slog.i(TAG, "cmd: handleResetAllThrottling");
4071
4072 resetAllThrottlingInner();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004073 }
4074
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004075 private void handleOverrideConfig() throws CommandException {
Makoto Onuki4362a662016-03-08 18:59:09 -08004076 final String config = getNextArgRequired();
4077
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004078 Slog.i(TAG, "cmd: handleOverrideConfig: " + config);
4079
Makoto Onuki4362a662016-03-08 18:59:09 -08004080 synchronized (mLock) {
4081 if (!updateConfigurationLocked(config)) {
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004082 throw new CommandException("override-config failed. See logcat for details.");
Makoto Onuki4362a662016-03-08 18:59:09 -08004083 }
4084 }
Makoto Onuki4362a662016-03-08 18:59:09 -08004085 }
4086
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004087 private void handleResetConfig() {
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004088 Slog.i(TAG, "cmd: handleResetConfig");
4089
Makoto Onuki4362a662016-03-08 18:59:09 -08004090 synchronized (mLock) {
4091 loadConfigurationLocked();
4092 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004093 }
4094
4095 private void clearLauncher() {
4096 synchronized (mLock) {
Makoto Onuki10305202016-07-14 18:14:08 -07004097 getUserShortcutsLocked(mUserId).forceClearLauncher();
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004098 }
4099 }
4100
4101 private void showLauncher() {
4102 synchronized (mLock) {
4103 // This ensures to set the cached launcher. Package name doesn't matter.
4104 hasShortcutHostPermissionInner("-", mUserId);
4105
4106 getOutPrintWriter().println("Launcher: "
Makoto Onuki10305202016-07-14 18:14:08 -07004107 + getUserShortcutsLocked(mUserId).getLastKnownLauncher());
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004108 }
4109 }
4110
4111 private void handleClearDefaultLauncher() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004112 synchronized (mLock) {
4113 parseOptionsLocked(/* takeUser =*/ true);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004114
Makoto Onuki02f338e2016-07-29 09:40:40 -07004115 clearLauncher();
4116 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004117 }
4118
4119 private void handleGetDefaultLauncher() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004120 synchronized (mLock) {
4121 parseOptionsLocked(/* takeUser =*/ true);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004122
Makoto Onuki02f338e2016-07-29 09:40:40 -07004123 clearLauncher();
4124 showLauncher();
4125 }
Makoto Onuki4362a662016-03-08 18:59:09 -08004126 }
Makoto Onukiac214972016-04-04 10:19:45 -07004127
4128 private void handleUnloadUser() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004129 synchronized (mLock) {
4130 parseOptionsLocked(/* takeUser =*/ true);
Makoto Onukiac214972016-04-04 10:19:45 -07004131
Makoto Onuki02f338e2016-07-29 09:40:40 -07004132 Slog.i(TAG, "cmd: handleUnloadUser: user=" + mUserId);
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004133
Makoto Onuki01ce92b2017-04-28 12:24:16 -07004134 ShortcutService.this.handleStopUser(mUserId);
Makoto Onuki02f338e2016-07-29 09:40:40 -07004135 }
Makoto Onukiac214972016-04-04 10:19:45 -07004136 }
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004137
4138 private void handleClearShortcuts() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004139 synchronized (mLock) {
4140 parseOptionsLocked(/* takeUser =*/ true);
4141 final String packageName = getNextArgRequired();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004142
Makoto Onuki02f338e2016-07-29 09:40:40 -07004143 Slog.i(TAG, "cmd: handleClearShortcuts: user" + mUserId + ", " + packageName);
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004144
Makoto Onuki02f338e2016-07-29 09:40:40 -07004145 ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId,
4146 /* appStillExists = */ true);
4147 }
Makoto Onukib08790c2016-06-23 14:05:46 -07004148 }
4149
4150 private void handleVerifyStates() throws CommandException {
4151 try {
4152 verifyStatesForce(); // This will throw when there's an issue.
4153 } catch (Throwable th) {
4154 throw new CommandException(th.getMessage() + "\n" + Log.getStackTraceString(th));
4155 }
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004156 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004157 }
4158
4159 // === Unit test support ===
4160
4161 // Injection point.
Makoto Onuki31459242016-03-22 11:12:18 -07004162 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004163 long injectCurrentTimeMillis() {
4164 return System.currentTimeMillis();
4165 }
4166
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07004167 @VisibleForTesting
4168 long injectElapsedRealtime() {
4169 return SystemClock.elapsedRealtime();
4170 }
4171
Makoto Onuki475c3652017-05-08 14:29:03 -07004172 @VisibleForTesting
4173 long injectUptimeMillis() {
4174 return SystemClock.uptimeMillis();
4175 }
4176
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004177 // Injection point.
Makoto Onuki31459242016-03-22 11:12:18 -07004178 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004179 int injectBinderCallingUid() {
4180 return getCallingUid();
4181 }
4182
Makoto Onuki31459242016-03-22 11:12:18 -07004183 private int getCallingUserId() {
Makoto Onuki4554d0e2016-03-14 15:51:41 -07004184 return UserHandle.getUserId(injectBinderCallingUid());
4185 }
4186
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07004187 // Injection point.
Makoto Onuki31459242016-03-22 11:12:18 -07004188 @VisibleForTesting
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07004189 long injectClearCallingIdentity() {
4190 return Binder.clearCallingIdentity();
4191 }
4192
4193 // Injection point.
Makoto Onuki31459242016-03-22 11:12:18 -07004194 @VisibleForTesting
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07004195 void injectRestoreCallingIdentity(long token) {
4196 Binder.restoreCallingIdentity(token);
4197 }
4198
Makoto Onuki33663282016-08-22 16:19:04 -07004199 // Injection point.
4200 @VisibleForTesting
4201 String injectBuildFingerprint() {
4202 return Build.FINGERPRINT;
4203 }
4204
Makoto Onukide667372016-03-15 14:29:20 -07004205 final void wtf(String message) {
Makoto Onukib08790c2016-06-23 14:05:46 -07004206 wtf(message, /* exception= */ null);
Makoto Onukide667372016-03-15 14:29:20 -07004207 }
4208
Makoto Onuki2e210c42016-03-30 08:30:36 -07004209 // Injection point.
Makoto Onukia2241832016-07-06 13:28:37 -07004210 void wtf(String message, Throwable e) {
4211 if (e == null) {
4212 e = new RuntimeException("Stacktrace");
4213 }
4214 synchronized (mLock) {
4215 mWtfCount++;
4216 mLastWtfStacktrace = new Exception("Last failure was logged here:");
4217 }
Makoto Onukide667372016-03-15 14:29:20 -07004218 Slog.wtf(TAG, message, e);
4219 }
4220
Makoto Onuki31459242016-03-22 11:12:18 -07004221 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004222 File injectSystemDataPath() {
4223 return Environment.getDataSystemDirectory();
4224 }
4225
Makoto Onuki31459242016-03-22 11:12:18 -07004226 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004227 File injectUserDataPath(@UserIdInt int userId) {
Makoto Onuki55046222016-03-08 10:49:47 -08004228 return new File(Environment.getDataSystemCeDirectory(userId), DIRECTORY_PER_USER);
4229 }
4230
Makoto Onuki50a320e2017-05-31 14:38:42 -07004231 public File getDumpPath() {
4232 return new File(injectUserDataPath(UserHandle.USER_SYSTEM), DIRECTORY_DUMP);
4233 }
4234
Makoto Onuki4362a662016-03-08 18:59:09 -08004235 @VisibleForTesting
Makoto Onuki55046222016-03-08 10:49:47 -08004236 boolean injectIsLowRamDevice() {
4237 return ActivityManager.isLowRamDeviceStatic();
4238 }
4239
Makoto Onuki31459242016-03-22 11:12:18 -07004240 @VisibleForTesting
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07004241 void injectRegisterUidObserver(IUidObserver observer, int which) {
4242 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004243 ActivityManager.getService().registerUidObserver(observer, which,
Dianne Hackborn5614bf52016-11-07 17:26:41 -08004244 ActivityManager.PROCESS_STATE_UNKNOWN, null);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07004245 } catch (RemoteException shouldntHappen) {
4246 }
4247 }
4248
Makoto Onuki55046222016-03-08 10:49:47 -08004249 File getUserBitmapFilePath(@UserIdInt int userId) {
4250 return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004251 }
4252
4253 @VisibleForTesting
Makoto Onuki31459242016-03-22 11:12:18 -07004254 SparseArray<ShortcutUser> getShortcutsForTest() {
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -08004255 return mUsers;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004256 }
4257
4258 @VisibleForTesting
Makoto Onukib5a012f2016-06-21 11:13:53 -07004259 int getMaxShortcutsForTest() {
4260 return mMaxShortcuts;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004261 }
4262
4263 @VisibleForTesting
Makoto Onukib6d35232016-04-04 15:57:17 -07004264 int getMaxUpdatesPerIntervalForTest() {
4265 return mMaxUpdatesPerInterval;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004266 }
4267
4268 @VisibleForTesting
Makoto Onuki4362a662016-03-08 18:59:09 -08004269 long getResetIntervalForTest() {
4270 return mResetInterval;
Makoto Onuki55046222016-03-08 10:49:47 -08004271 }
4272
4273 @VisibleForTesting
Makoto Onuki4362a662016-03-08 18:59:09 -08004274 int getMaxIconDimensionForTest() {
4275 return mMaxIconDimension;
4276 }
4277
4278 @VisibleForTesting
4279 CompressFormat getIconPersistFormatForTest() {
4280 return mIconPersistFormat;
4281 }
4282
4283 @VisibleForTesting
4284 int getIconPersistQualityForTest() {
4285 return mIconPersistQuality;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004286 }
Makoto Onuki41066a62016-03-09 16:18:44 -08004287
4288 @VisibleForTesting
Makoto Onuki22fcc682016-05-17 14:52:19 -07004289 ShortcutPackage getPackageShortcutForTest(String packageName, int userId) {
Makoto Onuki41066a62016-03-09 16:18:44 -08004290 synchronized (mLock) {
Makoto Onuki31459242016-03-22 11:12:18 -07004291 final ShortcutUser user = mUsers.get(userId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07004292 if (user == null) return null;
4293
Makoto Onuki22fcc682016-05-17 14:52:19 -07004294 return user.getAllPackagesForTest().get(packageName);
4295 }
4296 }
4297
4298 @VisibleForTesting
4299 ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) {
4300 synchronized (mLock) {
Makoto Onukif34c3082016-07-13 10:25:25 -07004301 final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07004302 if (pkg == null) return null;
4303
4304 return pkg.findShortcutById(shortcutId);
Makoto Onuki41066a62016-03-09 16:18:44 -08004305 }
4306 }
Makoto Onuki7001a612016-05-27 13:24:28 -07004307
Makoto Onukifac592f2016-11-21 13:41:32 -08004308 @VisibleForTesting
4309 ShortcutLauncher getLauncherShortcutForTest(String packageName, int userId) {
4310 synchronized (mLock) {
4311 final ShortcutUser user = mUsers.get(userId);
4312 if (user == null) return null;
4313
4314 return user.getAllLaunchersForTest().get(PackageWithUser.of(userId, packageName));
4315 }
4316 }
4317
Makoto Onuki2d895c32016-12-02 15:48:40 -08004318 @VisibleForTesting
4319 ShortcutRequestPinProcessor getShortcutRequestPinProcessorForTest() {
4320 return mShortcutRequestPinProcessor;
4321 }
4322
Makoto Onuki7001a612016-05-27 13:24:28 -07004323 /**
4324 * Control whether {@link #verifyStates} should be performed. We always perform it during unit
4325 * tests.
4326 */
4327 @VisibleForTesting
4328 boolean injectShouldPerformVerification() {
4329 return DEBUG;
4330 }
4331
4332 /**
4333 * Check various internal states and throws if there's any inconsistency.
4334 * This is normally only enabled during unit tests.
4335 */
4336 final void verifyStates() {
4337 if (injectShouldPerformVerification()) {
4338 verifyStatesInner();
4339 }
4340 }
4341
Makoto Onukib08790c2016-06-23 14:05:46 -07004342 private final void verifyStatesForce() {
4343 verifyStatesInner();
4344 }
4345
Makoto Onuki7001a612016-05-27 13:24:28 -07004346 private void verifyStatesInner() {
Makoto Onuki10305202016-07-14 18:14:08 -07004347 synchronized (mLock) {
Makoto Onuki7001a612016-05-27 13:24:28 -07004348 forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
4349 }
4350 }
Makoto Onuki475c3652017-05-08 14:29:03 -07004351
4352 @VisibleForTesting
4353 void waitForBitmapSavesForTest() {
4354 synchronized (mLock) {
4355 mShortcutBitmapSaver.waitForAllSavesLocked();
4356 }
4357 }
Makoto Onuki41066a62016-03-09 16:18:44 -08004358}