blob: d2bc6d24e2e9b7e9a1734d819d2d6f594e255a63 [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;
102import com.android.server.SystemService;
Makoto Onukid99c6f02016-03-28 11:02:54 -0700103import com.android.server.pm.ShortcutUser.PackageWithUser;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800104
105import libcore.io.IoUtils;
106
Makoto Onuki76269922016-07-15 14:58:54 -0700107import org.json.JSONArray;
108import org.json.JSONException;
109import org.json.JSONObject;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800110import org.xmlpull.v1.XmlPullParser;
111import org.xmlpull.v1.XmlPullParserException;
112import org.xmlpull.v1.XmlSerializer;
113
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700114import java.io.BufferedInputStream;
115import java.io.BufferedOutputStream;
116import java.io.ByteArrayInputStream;
117import java.io.ByteArrayOutputStream;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800118import java.io.File;
119import java.io.FileDescriptor;
120import java.io.FileInputStream;
121import java.io.FileNotFoundException;
122import java.io.FileOutputStream;
123import java.io.IOException;
Makoto Onuki55046222016-03-08 10:49:47 -0800124import java.io.InputStream;
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700125import java.io.OutputStream;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800126import java.io.PrintWriter;
Makoto Onuki7001a612016-05-27 13:24:28 -0700127import java.lang.annotation.Retention;
128import java.lang.annotation.RetentionPolicy;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800129import java.net.URISyntaxException;
130import java.nio.charset.StandardCharsets;
131import java.util.ArrayList;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700132import java.util.Collections;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800133import java.util.List;
Makoto Onukic51b2872016-05-04 15:24:50 -0700134import java.util.concurrent.atomic.AtomicBoolean;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700135import java.util.function.Consumer;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800136import java.util.function.Predicate;
Makoto Onuki20b82212017-10-04 15:03:50 -0700137import java.util.regex.Pattern;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800138
139/**
140 * TODO:
Makoto Onuki22fcc682016-05-17 14:52:19 -0700141 * - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi.
Makoto Onukib5a012f2016-06-21 11:13:53 -0700142 * -> But TypedValue.applyDimension() doesn't differentiate x and y..?
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800143 *
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700144 * - Detect when already registered instances are passed to APIs again, which might break
Makoto Onukib08790c2016-06-23 14:05:46 -0700145 * internal bitmap handling.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800146 */
147public class ShortcutService extends IShortcutService.Stub {
Makoto Onuki55046222016-03-08 10:49:47 -0800148 static final String TAG = "ShortcutService";
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800149
Makoto Onuki7001a612016-05-27 13:24:28 -0700150 static final boolean DEBUG = false; // STOPSHIP if true
Makoto Onuki41066a62016-03-09 16:18:44 -0800151 static final boolean DEBUG_LOAD = false; // STOPSHIP if true
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700152 static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800153
Makoto Onuki4362a662016-03-08 18:59:09 -0800154 @VisibleForTesting
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700155 static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
Makoto Onuki4362a662016-03-08 18:59:09 -0800156
157 @VisibleForTesting
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700158 static final int DEFAULT_MAX_UPDATES_PER_INTERVAL = 10;
Makoto Onuki4362a662016-03-08 18:59:09 -0800159
160 @VisibleForTesting
161 static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5;
162
163 @VisibleForTesting
164 static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96;
165
166 @VisibleForTesting
167 static final int DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP = 48;
168
169 @VisibleForTesting
170 static final String DEFAULT_ICON_PERSIST_FORMAT = CompressFormat.PNG.name();
171
172 @VisibleForTesting
173 static final int DEFAULT_ICON_PERSIST_QUALITY = 100;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800174
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700175 @VisibleForTesting
176 static final int DEFAULT_SAVE_DELAY_MS = 3000;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800177
178 @VisibleForTesting
179 static final String FILENAME_BASE_STATE = "shortcut_service.xml";
180
181 @VisibleForTesting
182 static final String DIRECTORY_PER_USER = "shortcut_service";
183
184 @VisibleForTesting
Makoto Onuki50a320e2017-05-31 14:38:42 -0700185 static final String DIRECTORY_DUMP = "shortcut_dump";
186
187 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800188 static final String FILENAME_USER_PACKAGES = "shortcuts.xml";
189
Makoto Onuki55046222016-03-08 10:49:47 -0800190 static final String DIRECTORY_BITMAPS = "bitmaps";
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800191
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700192 private static final String TAG_ROOT = "root";
193 private static final String TAG_LAST_RESET_TIME = "last_reset_time";
Makoto Onuki55046222016-03-08 10:49:47 -0800194
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700195 private static final String ATTR_VALUE = "value";
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800196
Makoto Onukib08790c2016-06-23 14:05:46 -0700197 private static final String LAUNCHER_INTENT_CATEGORY = Intent.CATEGORY_LAUNCHER;
198
Makoto Onuki76269922016-07-15 14:58:54 -0700199 private static final String KEY_SHORTCUT = "shortcut";
200 private static final String KEY_LOW_RAM = "lowRam";
201 private static final String KEY_ICON_SIZE = "iconSize";
202
Makoto Onuki2d895c32016-12-02 15:48:40 -0800203 private static final String DUMMY_MAIN_ACTIVITY = "android.__dummy__";
204
Makoto Onuki4362a662016-03-08 18:59:09 -0800205 @VisibleForTesting
206 interface ConfigConstants {
207 /**
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700208 * Key name for the save delay, in milliseconds. (int)
209 */
210 String KEY_SAVE_DELAY_MILLIS = "save_delay_ms";
211
212 /**
Makoto Onuki4362a662016-03-08 18:59:09 -0800213 * Key name for the throttling reset interval, in seconds. (long)
214 */
215 String KEY_RESET_INTERVAL_SEC = "reset_interval_sec";
216
217 /**
218 * Key name for the max number of modifying API calls per app for every interval. (int)
219 */
Makoto Onukib6d35232016-04-04 15:57:17 -0700220 String KEY_MAX_UPDATES_PER_INTERVAL = "max_updates_per_interval";
Makoto Onuki4362a662016-03-08 18:59:09 -0800221
222 /**
223 * Key name for the max icon dimensions in DP, for non-low-memory devices.
224 */
225 String KEY_MAX_ICON_DIMENSION_DP = "max_icon_dimension_dp";
226
227 /**
228 * Key name for the max icon dimensions in DP, for low-memory devices.
229 */
230 String KEY_MAX_ICON_DIMENSION_DP_LOWRAM = "max_icon_dimension_dp_lowram";
231
232 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700233 * Key name for the max dynamic shortcuts per activity. (int)
Makoto Onuki4362a662016-03-08 18:59:09 -0800234 */
235 String KEY_MAX_SHORTCUTS = "max_shortcuts";
236
237 /**
Makoto Onuki41066a62016-03-09 16:18:44 -0800238 * Key name for icon compression quality, 0-100.
Makoto Onuki4362a662016-03-08 18:59:09 -0800239 */
240 String KEY_ICON_QUALITY = "icon_quality";
241
242 /**
243 * Key name for icon compression format: "PNG", "JPEG" or "WEBP"
244 */
245 String KEY_ICON_FORMAT = "icon_format";
246 }
247
Makoto Onuki41066a62016-03-09 16:18:44 -0800248 final Context mContext;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800249
250 private final Object mLock = new Object();
251
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700252 private static List<ResolveInfo> EMPTY_RESOLVE_INFO = new ArrayList<>(0);
253
Mark Renoufe065f7c2016-11-01 11:48:24 -0400254 // Temporarily reverted to anonymous inner class form due to: b/32554459
255 private static Predicate<ResolveInfo> ACTIVITY_NOT_EXPORTED = new Predicate<ResolveInfo>() {
256 public boolean test(ResolveInfo ri) {
257 return !ri.activityInfo.exported;
258 }
259 };
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700260
Mark Renoufe065f7c2016-11-01 11:48:24 -0400261 // Temporarily reverted to anonymous inner class form due to: b/32554459
262 private static Predicate<PackageInfo> PACKAGE_NOT_INSTALLED = new Predicate<PackageInfo>() {
263 public boolean test(PackageInfo pi) {
264 return !isInstalled(pi);
265 }
266 };
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700267
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800268 private final Handler mHandler;
269
270 @GuardedBy("mLock")
271 private final ArrayList<ShortcutChangeListener> mListeners = new ArrayList<>(1);
272
273 @GuardedBy("mLock")
274 private long mRawLastResetTime;
275
276 /**
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -0800277 * User ID -> UserShortcuts
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800278 */
279 @GuardedBy("mLock")
Makoto Onuki31459242016-03-22 11:12:18 -0700280 private final SparseArray<ShortcutUser> mUsers = new SparseArray<>();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800281
282 /**
Makoto Onuki708703b2017-12-11 16:38:11 -0800283 * User ID -> ShortcutNonPersistentUser
284 */
285 @GuardedBy("mLock")
286 private final SparseArray<ShortcutNonPersistentUser> mShortcutNonPersistentUsers =
287 new SparseArray<>();
288
289 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700290 * Max number of dynamic + manifest shortcuts that each application can have at a time.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800291 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700292 private int mMaxShortcuts;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800293
294 /**
Makoto Onukib6d35232016-04-04 15:57:17 -0700295 * Max number of updating API calls that each application can make during the interval.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800296 */
Makoto Onukib6d35232016-04-04 15:57:17 -0700297 int mMaxUpdatesPerInterval;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800298
299 /**
300 * Actual throttling-reset interval. By default it's a day.
301 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800302 private long mResetInterval;
303
Makoto Onuki55046222016-03-08 10:49:47 -0800304 /**
305 * Icon max width/height in pixels.
306 */
307 private int mMaxIconDimension;
308
Makoto Onuki4362a662016-03-08 18:59:09 -0800309 private CompressFormat mIconPersistFormat;
310 private int mIconPersistQuality;
Makoto Onuki55046222016-03-08 10:49:47 -0800311
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700312 private int mSaveDelayMillis;
313
Makoto Onuki0acbb142016-03-22 17:02:57 -0700314 private final IPackageManager mIPackageManager;
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800315 private final PackageManagerInternal mPackageManagerInternal;
Makoto Onukicdc78f72016-03-21 15:47:52 -0700316 private final UserManager mUserManager;
Makoto Onukiac042502016-05-20 16:39:42 -0700317 private final UsageStatsManagerInternal mUsageStatsManagerInternal;
Makoto Onuki33525d22016-08-03 15:45:24 -0700318 private final ActivityManagerInternal mActivityManagerInternal;
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800319
Makoto Onuki2d895c32016-12-02 15:48:40 -0800320 private final ShortcutRequestPinProcessor mShortcutRequestPinProcessor;
Makoto Onuki475c3652017-05-08 14:29:03 -0700321 private final ShortcutBitmapSaver mShortcutBitmapSaver;
Makoto Onuki50a320e2017-05-31 14:38:42 -0700322 private final ShortcutDumpFiles mShortcutDumpFiles;
Makoto Onuki2d895c32016-12-02 15:48:40 -0800323
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700324 @GuardedBy("mLock")
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700325 final SparseIntArray mUidState = new SparseIntArray();
326
327 @GuardedBy("mLock")
328 final SparseLongArray mUidLastForegroundElapsedTime = new SparseLongArray();
329
330 @GuardedBy("mLock")
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700331 private List<Integer> mDirtyUserIds = new ArrayList<>();
332
Makoto Onukic51b2872016-05-04 15:24:50 -0700333 private final AtomicBoolean mBootCompleted = new AtomicBoolean();
334
Makoto Onuki905e8852016-03-28 10:40:58 -0700335 private static final int PACKAGE_MATCH_FLAGS =
336 PackageManager.MATCH_DIRECT_BOOT_AWARE
Makoto Onukib08790c2016-06-23 14:05:46 -0700337 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
338 | PackageManager.MATCH_UNINSTALLED_PACKAGES;
Makoto Onuki905e8852016-03-28 10:40:58 -0700339
Makoto Onukie63b04a2017-12-11 14:47:19 -0800340 /**
341 * Note we use a fine-grained lock for {@link #mUnlockedUsers} due to b/64303666.
342 */
343 @GuardedBy("mUnlockedUsers")
Makoto Onuki02f338e2016-07-29 09:40:40 -0700344 final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
345
Makoto Onuki2e210c42016-03-30 08:30:36 -0700346 // Stats
347 @VisibleForTesting
348 interface Stats {
349 int GET_DEFAULT_HOME = 0;
350 int GET_PACKAGE_INFO = 1;
351 int GET_PACKAGE_INFO_WITH_SIG = 2;
352 int GET_APPLICATION_INFO = 3;
353 int LAUNCHER_PERMISSION_CHECK = 4;
Makoto Onuki6c1dbd52016-05-02 15:19:32 -0700354 int CLEANUP_DANGLING_BITMAPS = 5;
Makoto Onukib08790c2016-06-23 14:05:46 -0700355 int GET_ACTIVITY_WITH_METADATA = 6;
Makoto Onuki6dd9fb72016-06-01 13:55:54 -0700356 int GET_INSTALLED_PACKAGES = 7;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700357 int CHECK_PACKAGE_CHANGES = 8;
Makoto Onuki157b1622016-06-02 16:13:10 -0700358 int GET_APPLICATION_RESOURCES = 9;
359 int RESOURCE_NAME_LOOKUP = 10;
Makoto Onukib08790c2016-06-23 14:05:46 -0700360 int GET_LAUNCHER_ACTIVITY = 11;
361 int CHECK_LAUNCHER_ACTIVITY = 12;
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700362 int IS_ACTIVITY_ENABLED = 13;
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700363 int PACKAGE_UPDATE_CHECK = 14;
Makoto Onuki085a05c2016-08-19 11:39:29 -0700364 int ASYNC_PRELOAD_USER_DELAY = 15;
Makoto Onuki2d895c32016-12-02 15:48:40 -0800365 int GET_DEFAULT_LAUNCHER = 16;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700366
Makoto Onuki2d895c32016-12-02 15:48:40 -0800367 int COUNT = GET_DEFAULT_LAUNCHER + 1;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700368 }
369
Makoto Onuki085a05c2016-08-19 11:39:29 -0700370 private static final String[] STAT_LABELS = {
371 "getHomeActivities()",
372 "Launcher permission check",
373 "getPackageInfo()",
374 "getPackageInfo(SIG)",
375 "getApplicationInfo",
376 "cleanupDanglingBitmaps",
377 "getActivity+metadata",
378 "getInstalledPackages",
379 "checkPackageChanges",
380 "getApplicationResources",
381 "resourceNameLookup",
382 "getLauncherActivity",
383 "checkLauncherActivity",
384 "isActivityEnabled",
385 "packageUpdateCheck",
Makoto Onuki2d895c32016-12-02 15:48:40 -0800386 "asyncPreloadUserDelay",
387 "getDefaultLauncher()"
Makoto Onuki085a05c2016-08-19 11:39:29 -0700388 };
389
Makoto Onuki2e210c42016-03-30 08:30:36 -0700390 final Object mStatLock = new Object();
391
392 @GuardedBy("mStatLock")
393 private final int[] mCountStats = new int[Stats.COUNT];
394
395 @GuardedBy("mStatLock")
396 private final long[] mDurationStats = new long[Stats.COUNT];
397
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700398 private static final int PROCESS_STATE_FOREGROUND_THRESHOLD =
Dianne Hackborn10fc4fd2017-12-19 17:23:13 -0800399 ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700400
Makoto Onuki7001a612016-05-27 13:24:28 -0700401 static final int OPERATION_SET = 0;
402 static final int OPERATION_ADD = 1;
403 static final int OPERATION_UPDATE = 2;
404
405 /** @hide */
406 @IntDef(value = {
407 OPERATION_SET,
408 OPERATION_ADD,
409 OPERATION_UPDATE
Makoto Onukib08790c2016-06-23 14:05:46 -0700410 })
Makoto Onuki7001a612016-05-27 13:24:28 -0700411 @Retention(RetentionPolicy.SOURCE)
Makoto Onukib08790c2016-06-23 14:05:46 -0700412 @interface ShortcutOperation {
413 }
Makoto Onuki7001a612016-05-27 13:24:28 -0700414
Makoto Onukia2241832016-07-06 13:28:37 -0700415 @GuardedBy("mLock")
416 private int mWtfCount = 0;
417
418 @GuardedBy("mLock")
419 private Exception mLastWtfStacktrace;
420
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700421 static class InvalidFileFormatException extends Exception {
422 public InvalidFileFormatException(String message, Throwable cause) {
423 super(message, cause);
424 }
425 }
426
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800427 public ShortcutService(Context context) {
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700428 this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700429 }
430
431 @VisibleForTesting
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700432 ShortcutService(Context context, Looper looper, boolean onlyForPackageManagerApis) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800433 mContext = Preconditions.checkNotNull(context);
434 LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700435 mHandler = new Handler(looper);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700436 mIPackageManager = AppGlobals.getPackageManager();
Makoto Onukiac042502016-05-20 16:39:42 -0700437 mPackageManagerInternal = Preconditions.checkNotNull(
438 LocalServices.getService(PackageManagerInternal.class));
439 mUserManager = Preconditions.checkNotNull(context.getSystemService(UserManager.class));
440 mUsageStatsManagerInternal = Preconditions.checkNotNull(
441 LocalServices.getService(UsageStatsManagerInternal.class));
Makoto Onuki33525d22016-08-03 15:45:24 -0700442 mActivityManagerInternal = Preconditions.checkNotNull(
443 LocalServices.getService(ActivityManagerInternal.class));
Makoto Onukicdc78f72016-03-21 15:47:52 -0700444
Makoto Onuki2d895c32016-12-02 15:48:40 -0800445 mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock);
Makoto Onuki475c3652017-05-08 14:29:03 -0700446 mShortcutBitmapSaver = new ShortcutBitmapSaver(this);
Makoto Onuki50a320e2017-05-31 14:38:42 -0700447 mShortcutDumpFiles = new ShortcutDumpFiles(this);
Makoto Onuki2d895c32016-12-02 15:48:40 -0800448
Makoto Onukiee6b6e42016-06-29 17:34:02 -0700449 if (onlyForPackageManagerApis) {
450 return; // Don't do anything further. For unit tests only.
451 }
452
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700453 // Register receivers.
454
455 // We need to set a priority, so let's just not use PackageMonitor for now.
456 // TODO Refactor PackageMonitor to support priorities.
457 final IntentFilter packageFilter = new IntentFilter();
458 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
459 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
460 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
461 packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
462 packageFilter.addDataScheme("package");
463 packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
464 mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
465 packageFilter, null, mHandler);
466
Makoto Onuki10305202016-07-14 18:14:08 -0700467 final IntentFilter preferedActivityFilter = new IntentFilter();
468 preferedActivityFilter.addAction(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED);
469 preferedActivityFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
470 mContext.registerReceiverAsUser(mPackageMonitor, UserHandle.ALL,
471 preferedActivityFilter, null, mHandler);
472
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700473 final IntentFilter localeFilter = new IntentFilter();
474 localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
475 localeFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
476 mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL,
477 localeFilter, null, mHandler);
Makoto Onukif34c3082016-07-13 10:25:25 -0700478
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700479 injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
480 | ActivityManager.UID_OBSERVER_GONE);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800481 }
482
Makoto Onuki2e210c42016-03-30 08:30:36 -0700483 void logDurationStat(int statId, long start) {
484 synchronized (mStatLock) {
485 mCountStats[statId]++;
Makoto Onuki6c1dbd52016-05-02 15:19:32 -0700486 mDurationStats[statId] += (injectElapsedRealtime() - start);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700487 }
488 }
489
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700490 public String injectGetLocaleTagsForUser(@UserIdInt int userId) {
491 // TODO This should get the per-user locale. b/30123329 b/30119489
492 return LocaleList.getDefault().toLanguageTags();
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700493 }
494
495 final private IUidObserver mUidObserver = new IUidObserver.Stub() {
Makoto Onukib08790c2016-06-23 14:05:46 -0700496 @Override
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700497 public void onUidStateChanged(int uid, int procState, long procStateSeq) {
Makoto Onukidc3f6d12017-09-22 17:22:50 -0700498 injectPostToHandler(() -> handleOnUidStateChanged(uid, procState));
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 onUidGone(int uid, boolean disabled) {
Makoto Onukidc3f6d12017-09-22 17:22:50 -0700503 injectPostToHandler(() ->
504 handleOnUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT));
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700505 }
506
Makoto Onukib08790c2016-06-23 14:05:46 -0700507 @Override
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700508 public void onUidActive(int uid) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700509 }
510
Makoto Onukib08790c2016-06-23 14:05:46 -0700511 @Override
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700512 public void onUidIdle(int uid, boolean disabled) {
513 }
514
515 @Override public void onUidCachedChanged(int uid, boolean cached) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700516 }
517 };
518
519 void handleOnUidStateChanged(int uid, int procState) {
520 if (DEBUG_PROCSTATE) {
521 Slog.d(TAG, "onUidStateChanged: uid=" + uid + " state=" + procState);
522 }
523 synchronized (mLock) {
524 mUidState.put(uid, procState);
525
526 // We need to keep track of last time an app comes to foreground.
527 // See ShortcutPackage.getApiCallCount() for how it's used.
528 // It doesn't have to be persisted, but it needs to be the elapsed time.
529 if (isProcessStateForeground(procState)) {
530 mUidLastForegroundElapsedTime.put(uid, injectElapsedRealtime());
531 }
532 }
533 }
534
535 private boolean isProcessStateForeground(int processState) {
Dianne Hackborn5614bf52016-11-07 17:26:41 -0800536 return processState <= PROCESS_STATE_FOREGROUND_THRESHOLD;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700537 }
538
539 boolean isUidForegroundLocked(int uid) {
540 if (uid == Process.SYSTEM_UID) {
541 // IUidObserver doesn't report the state of SYSTEM, but it always has bound services,
542 // so it's foreground anyway.
543 return true;
544 }
Makoto Onuki33525d22016-08-03 15:45:24 -0700545 // First, check with the local cache.
546 if (isProcessStateForeground(mUidState.get(uid, ActivityManager.MAX_PROCESS_STATE))) {
547 return true;
548 }
549 // If the cache says background, reach out to AM. Since it'll internally need to hold
550 // the AM lock, we use it as a last resort.
551 return isProcessStateForeground(mActivityManagerInternal.getUidProcessState(uid));
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700552 }
553
554 long getUidLastForegroundElapsedTimeLocked(int uid) {
555 return mUidLastForegroundElapsedTime.get(uid);
556 }
557
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800558 /**
559 * System service lifecycle.
560 */
561 public static final class Lifecycle extends SystemService {
562 final ShortcutService mService;
563
564 public Lifecycle(Context context) {
565 super(context);
Makoto Onukia4f89b12017-10-05 10:37:55 -0700566 if (DEBUG) {
567 Binder.LOG_RUNTIME_EXCEPTION = true;
568 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800569 mService = new ShortcutService(context);
570 }
571
572 @Override
573 public void onStart() {
574 publishBinderService(Context.SHORTCUT_SERVICE, mService);
575 }
576
577 @Override
578 public void onBootPhase(int phase) {
579 mService.onBootPhase(phase);
580 }
581
582 @Override
Makoto Onuki01ce92b2017-04-28 12:24:16 -0700583 public void onStopUser(int userHandle) {
584 mService.handleStopUser(userHandle);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800585 }
586
587 @Override
Makoto Onukif3a572b2016-03-10 12:28:38 -0800588 public void onUnlockUser(int userId) {
Makoto Onukicdc78f72016-03-21 15:47:52 -0700589 mService.handleUnlockUser(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800590 }
591 }
592
593 /** lifecycle event */
594 void onBootPhase(int phase) {
595 if (DEBUG) {
596 Slog.d(TAG, "onBootPhase: " + phase);
597 }
598 switch (phase) {
599 case SystemService.PHASE_LOCK_SETTINGS_READY:
600 initialize();
601 break;
Makoto Onukic51b2872016-05-04 15:24:50 -0700602 case SystemService.PHASE_BOOT_COMPLETED:
603 mBootCompleted.set(true);
604 break;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800605 }
606 }
607
608 /** lifecycle event */
Makoto Onukicdc78f72016-03-21 15:47:52 -0700609 void handleUnlockUser(int userId) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700610 if (DEBUG) {
Makoto Onuki085a05c2016-08-19 11:39:29 -0700611 Slog.d(TAG, "handleUnlockUser: user=" + userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -0700612 }
Makoto Onukie63b04a2017-12-11 14:47:19 -0800613 synchronized (mUnlockedUsers) {
Makoto Onuki02f338e2016-07-29 09:40:40 -0700614 mUnlockedUsers.put(userId, true);
Makoto Onukicdc78f72016-03-21 15:47:52 -0700615 }
Makoto Onuki085a05c2016-08-19 11:39:29 -0700616
617 // Preload the user data.
618 // Note, we don't use mHandler here but instead just start a new thread.
619 // This is because mHandler (which uses com.android.internal.os.BackgroundThread) is very
620 // busy at this point and this could take hundreds of milliseconds, which would be too
621 // late since the launcher would already have started.
622 // So we just create a new thread. This code runs rarely, so we don't use a thread pool
623 // or anything.
624 final long start = injectElapsedRealtime();
625 injectRunOnNewThread(() -> {
626 synchronized (mLock) {
627 logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
628 getUserShortcutsLocked(userId);
629 }
630 });
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800631 }
632
633 /** lifecycle event */
Makoto Onuki01ce92b2017-04-28 12:24:16 -0700634 void handleStopUser(int userId) {
Makoto Onuki02f338e2016-07-29 09:40:40 -0700635 if (DEBUG) {
Makoto Onuki01ce92b2017-04-28 12:24:16 -0700636 Slog.d(TAG, "handleStopUser: user=" + userId);
Makoto Onuki02f338e2016-07-29 09:40:40 -0700637 }
Makoto Onukicdc78f72016-03-21 15:47:52 -0700638 synchronized (mLock) {
639 unloadUserLocked(userId);
Makoto Onuki02f338e2016-07-29 09:40:40 -0700640
Makoto Onukie63b04a2017-12-11 14:47:19 -0800641 synchronized (mUnlockedUsers) {
642 mUnlockedUsers.put(userId, false);
643 }
Makoto Onukicdc78f72016-03-21 15:47:52 -0700644 }
645 }
646
647 private void unloadUserLocked(int userId) {
648 if (DEBUG) {
649 Slog.d(TAG, "unloadUserLocked: user=" + userId);
650 }
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700651 // Save all dirty information.
652 saveDirtyInfo();
653
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800654 // Unload
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -0800655 mUsers.delete(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800656 }
657
658 /** Return the base state file name */
659 private AtomicFile getBaseStateFile() {
660 final File path = new File(injectSystemDataPath(), FILENAME_BASE_STATE);
661 path.mkdirs();
662 return new AtomicFile(path);
663 }
664
665 /**
666 * Init the instance. (load the state file, etc)
667 */
668 private void initialize() {
669 synchronized (mLock) {
Makoto Onuki4362a662016-03-08 18:59:09 -0800670 loadConfigurationLocked();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800671 loadBaseStateLocked();
672 }
673 }
674
Makoto Onuki4362a662016-03-08 18:59:09 -0800675 /**
676 * Load the configuration from Settings.
677 */
678 private void loadConfigurationLocked() {
679 updateConfigurationLocked(injectShortcutManagerConstants());
680 }
Makoto Onuki55046222016-03-08 10:49:47 -0800681
Makoto Onuki4362a662016-03-08 18:59:09 -0800682 /**
683 * Load the configuration from Settings.
684 */
685 @VisibleForTesting
686 boolean updateConfigurationLocked(String config) {
687 boolean result = true;
688
689 final KeyValueListParser parser = new KeyValueListParser(',');
690 try {
691 parser.setString(config);
692 } catch (IllegalArgumentException e) {
693 // Failed to parse the settings string, log this and move on
694 // with defaults.
695 Slog.e(TAG, "Bad shortcut manager settings", e);
696 result = false;
697 }
698
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700699 mSaveDelayMillis = Math.max(0, (int) parser.getLong(ConfigConstants.KEY_SAVE_DELAY_MILLIS,
700 DEFAULT_SAVE_DELAY_MS));
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700701
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700702 mResetInterval = Math.max(1, parser.getLong(
Makoto Onuki4362a662016-03-08 18:59:09 -0800703 ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC)
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700704 * 1000L);
Makoto Onuki4362a662016-03-08 18:59:09 -0800705
Makoto Onukib6d35232016-04-04 15:57:17 -0700706 mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong(
707 ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL));
Makoto Onuki4362a662016-03-08 18:59:09 -0800708
Makoto Onukib5a012f2016-06-21 11:13:53 -0700709 mMaxShortcuts = Math.max(0, (int) parser.getLong(
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700710 ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP));
Makoto Onuki4362a662016-03-08 18:59:09 -0800711
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700712 final int iconDimensionDp = Math.max(1, injectIsLowRamDevice()
Makoto Onuki4362a662016-03-08 18:59:09 -0800713 ? (int) parser.getLong(
Makoto Onukib08790c2016-06-23 14:05:46 -0700714 ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM,
715 DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP)
Makoto Onuki4362a662016-03-08 18:59:09 -0800716 : (int) parser.getLong(
Makoto Onukib08790c2016-06-23 14:05:46 -0700717 ConfigConstants.KEY_MAX_ICON_DIMENSION_DP,
718 DEFAULT_MAX_ICON_DIMENSION_DP));
Makoto Onuki4362a662016-03-08 18:59:09 -0800719
720 mMaxIconDimension = injectDipToPixel(iconDimensionDp);
721
722 mIconPersistFormat = CompressFormat.valueOf(
723 parser.getString(ConfigConstants.KEY_ICON_FORMAT, DEFAULT_ICON_PERSIST_FORMAT));
724
725 mIconPersistQuality = (int) parser.getLong(
726 ConfigConstants.KEY_ICON_QUALITY,
727 DEFAULT_ICON_PERSIST_QUALITY);
728
729 return result;
730 }
731
732 @VisibleForTesting
733 String injectShortcutManagerConstants() {
734 return android.provider.Settings.Global.getString(
735 mContext.getContentResolver(),
736 android.provider.Settings.Global.SHORTCUT_MANAGER_CONSTANTS);
737 }
738
739 @VisibleForTesting
740 int injectDipToPixel(int dip) {
741 return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
742 mContext.getResources().getDisplayMetrics());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800743 }
744
Makoto Onuki55046222016-03-08 10:49:47 -0800745 // === Persisting ===
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800746
747 @Nullable
Makoto Onuki41066a62016-03-09 16:18:44 -0800748 static String parseStringAttribute(XmlPullParser parser, String attribute) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800749 return parser.getAttributeValue(null, attribute);
750 }
751
Makoto Onuki0acbb142016-03-22 17:02:57 -0700752 static boolean parseBooleanAttribute(XmlPullParser parser, String attribute) {
753 return parseLongAttribute(parser, attribute) == 1;
754 }
755
Makoto Onukia4f89b12017-10-05 10:37:55 -0700756 static boolean parseBooleanAttribute(XmlPullParser parser, String attribute, boolean def) {
757 return parseLongAttribute(parser, attribute, (def ? 1 : 0)) == 1;
758 }
759
Makoto Onuki41066a62016-03-09 16:18:44 -0800760 static int parseIntAttribute(XmlPullParser parser, String attribute) {
761 return (int) parseLongAttribute(parser, attribute);
762 }
763
Makoto Onukid99c6f02016-03-28 11:02:54 -0700764 static int parseIntAttribute(XmlPullParser parser, String attribute, int def) {
765 return (int) parseLongAttribute(parser, attribute, def);
766 }
767
Makoto Onuki41066a62016-03-09 16:18:44 -0800768 static long parseLongAttribute(XmlPullParser parser, String attribute) {
Makoto Onukid99c6f02016-03-28 11:02:54 -0700769 return parseLongAttribute(parser, attribute, 0);
770 }
771
772 static long parseLongAttribute(XmlPullParser parser, String attribute, long def) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800773 final String value = parseStringAttribute(parser, attribute);
774 if (TextUtils.isEmpty(value)) {
Makoto Onukid99c6f02016-03-28 11:02:54 -0700775 return def;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800776 }
777 try {
778 return Long.parseLong(value);
779 } catch (NumberFormatException e) {
780 Slog.e(TAG, "Error parsing long " + value);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700781 return def;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800782 }
783 }
784
785 @Nullable
Makoto Onuki41066a62016-03-09 16:18:44 -0800786 static ComponentName parseComponentNameAttribute(XmlPullParser parser, String attribute) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800787 final String value = parseStringAttribute(parser, attribute);
788 if (TextUtils.isEmpty(value)) {
789 return null;
790 }
791 return ComponentName.unflattenFromString(value);
792 }
793
794 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700795 static Intent parseIntentAttributeNoDefault(XmlPullParser parser, String attribute) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800796 final String value = parseStringAttribute(parser, attribute);
Makoto Onukib5a012f2016-06-21 11:13:53 -0700797 Intent parsed = null;
798 if (!TextUtils.isEmpty(value)) {
799 try {
800 parsed = Intent.parseUri(value, /* flags =*/ 0);
801 } catch (URISyntaxException e) {
802 Slog.e(TAG, "Error parsing intent", e);
803 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800804 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700805 return parsed;
806 }
807
808 @Nullable
809 static Intent parseIntentAttribute(XmlPullParser parser, String attribute) {
810 Intent parsed = parseIntentAttributeNoDefault(parser, attribute);
Makoto Onukib5a012f2016-06-21 11:13:53 -0700811 if (parsed == null) {
812 // Default intent.
813 parsed = new Intent(Intent.ACTION_VIEW);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800814 }
Makoto Onukib5a012f2016-06-21 11:13:53 -0700815 return parsed;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800816 }
817
Makoto Onuki41066a62016-03-09 16:18:44 -0800818 static void writeTagValue(XmlSerializer out, String tag, String value) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800819 if (TextUtils.isEmpty(value)) return;
820
821 out.startTag(null, tag);
822 out.attribute(null, ATTR_VALUE, value);
823 out.endTag(null, tag);
824 }
825
Makoto Onuki41066a62016-03-09 16:18:44 -0800826 static void writeTagValue(XmlSerializer out, String tag, long value) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800827 writeTagValue(out, tag, Long.toString(value));
828 }
829
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800830 static void writeTagValue(XmlSerializer out, String tag, ComponentName name) throws IOException {
831 if (name == null) return;
832 writeTagValue(out, tag, name.flattenToString());
833 }
834
Makoto Onuki41066a62016-03-09 16:18:44 -0800835 static void writeTagExtra(XmlSerializer out, String tag, PersistableBundle bundle)
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800836 throws IOException, XmlPullParserException {
837 if (bundle == null) return;
838
839 out.startTag(null, tag);
840 bundle.saveToXml(out);
841 out.endTag(null, tag);
842 }
843
Makoto Onuki22fcc682016-05-17 14:52:19 -0700844 static void writeAttr(XmlSerializer out, String name, CharSequence value) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800845 if (TextUtils.isEmpty(value)) return;
846
Makoto Onuki22fcc682016-05-17 14:52:19 -0700847 out.attribute(null, name, value.toString());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800848 }
849
Makoto Onuki41066a62016-03-09 16:18:44 -0800850 static void writeAttr(XmlSerializer out, String name, long value) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800851 writeAttr(out, name, String.valueOf(value));
852 }
853
Makoto Onuki0acbb142016-03-22 17:02:57 -0700854 static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException {
855 if (value) {
856 writeAttr(out, name, "1");
Makoto Onukia4f89b12017-10-05 10:37:55 -0700857 } else {
858 writeAttr(out, name, "0");
Makoto Onuki0acbb142016-03-22 17:02:57 -0700859 }
860 }
861
Makoto Onuki41066a62016-03-09 16:18:44 -0800862 static void writeAttr(XmlSerializer out, String name, ComponentName comp) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800863 if (comp == null) return;
864 writeAttr(out, name, comp.flattenToString());
865 }
866
Makoto Onuki41066a62016-03-09 16:18:44 -0800867 static void writeAttr(XmlSerializer out, String name, Intent intent) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800868 if (intent == null) return;
869
870 writeAttr(out, name, intent.toUri(/* flags =*/ 0));
871 }
872
873 @VisibleForTesting
874 void saveBaseStateLocked() {
875 final AtomicFile file = getBaseStateFile();
876 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700877 Slog.d(TAG, "Saving to " + file.getBaseFile());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800878 }
879
880 FileOutputStream outs = null;
881 try {
882 outs = file.startWrite();
883
884 // Write to XML
885 XmlSerializer out = new FastXmlSerializer();
886 out.setOutput(outs, StandardCharsets.UTF_8.name());
887 out.startDocument(null, true);
888 out.startTag(null, TAG_ROOT);
889
890 // Body.
891 writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime);
892
893 // Epilogue.
894 out.endTag(null, TAG_ROOT);
895 out.endDocument();
896
897 // Close.
898 file.finishWrite(outs);
899 } catch (IOException e) {
900 Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
901 file.failWrite(outs);
902 }
903 }
904
905 private void loadBaseStateLocked() {
906 mRawLastResetTime = 0;
907
908 final AtomicFile file = getBaseStateFile();
909 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700910 Slog.d(TAG, "Loading from " + file.getBaseFile());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800911 }
912 try (FileInputStream in = file.openRead()) {
913 XmlPullParser parser = Xml.newPullParser();
914 parser.setInput(in, StandardCharsets.UTF_8.name());
915
916 int type;
917 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
918 if (type != XmlPullParser.START_TAG) {
919 continue;
920 }
921 final int depth = parser.getDepth();
922 // Check the root tag
923 final String tag = parser.getName();
924 if (depth == 1) {
925 if (!TAG_ROOT.equals(tag)) {
926 Slog.e(TAG, "Invalid root tag: " + tag);
927 return;
928 }
929 continue;
930 }
931 // Assume depth == 2
932 switch (tag) {
933 case TAG_LAST_RESET_TIME:
934 mRawLastResetTime = parseLongAttribute(parser, ATTR_VALUE);
935 break;
936 default:
937 Slog.e(TAG, "Invalid tag: " + tag);
938 break;
939 }
940 }
941 } catch (FileNotFoundException e) {
942 // Use the default
Makoto Onukib08790c2016-06-23 14:05:46 -0700943 } catch (IOException | XmlPullParserException e) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800944 Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
945
946 mRawLastResetTime = 0;
947 }
948 // Adjust the last reset time.
949 getLastResetTimeLocked();
950 }
951
Makoto Onuki0eed4412016-07-21 11:21:59 -0700952 @VisibleForTesting
953 final File getUserFile(@UserIdInt int userId) {
954 return new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
955 }
956
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800957 private void saveUserLocked(@UserIdInt int userId) {
Makoto Onuki0eed4412016-07-21 11:21:59 -0700958 final File path = getUserFile(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800959 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -0700960 Slog.d(TAG, "Saving to " + path);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800961 }
Makoto Onuki475c3652017-05-08 14:29:03 -0700962
963 mShortcutBitmapSaver.waitForAllSavesLocked();
964
Makoto Onuki0eed4412016-07-21 11:21:59 -0700965 path.getParentFile().mkdirs();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800966 final AtomicFile file = new AtomicFile(path);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700967 FileOutputStream os = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800968 try {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700969 os = file.startWrite();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800970
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700971 saveUserInternalLocked(userId, os, /* forBackup= */ false);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800972
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700973 file.finishWrite(os);
Makoto Onuki1e173232016-08-10 10:47:13 -0700974
975 // Remove all dangling bitmap files.
976 cleanupDanglingBitmapDirectoriesLocked(userId);
Makoto Onukib08790c2016-06-23 14:05:46 -0700977 } catch (XmlPullParserException | IOException e) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800978 Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700979 file.failWrite(os);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800980 }
981 }
982
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700983 private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
984 boolean forBackup) throws IOException, XmlPullParserException {
985
986 final BufferedOutputStream bos = new BufferedOutputStream(os);
987
988 // Write to XML
989 XmlSerializer out = new FastXmlSerializer();
990 out.setOutput(bos, StandardCharsets.UTF_8.name());
991 out.startDocument(null, true);
992
Makoto Onukic51b2872016-05-04 15:24:50 -0700993 getUserShortcutsLocked(userId).saveToXml(out, forBackup);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700994
995 out.endDocument();
996
997 bos.flush();
998 os.flush();
999 }
1000
Makoto Onuki41066a62016-03-09 16:18:44 -08001001 static IOException throwForInvalidTag(int depth, String tag) throws IOException {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001002 throw new IOException(String.format("Invalid tag '%s' found at depth %d", tag, depth));
1003 }
1004
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001005 static void warnForInvalidTag(int depth, String tag) throws IOException {
1006 Slog.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth));
1007 }
1008
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001009 @Nullable
Makoto Onuki31459242016-03-22 11:12:18 -07001010 private ShortcutUser loadUserLocked(@UserIdInt int userId) {
Makoto Onuki0eed4412016-07-21 11:21:59 -07001011 final File path = getUserFile(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001012 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001013 Slog.d(TAG, "Loading from " + path);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001014 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001015 final AtomicFile file = new AtomicFile(path);
1016
1017 final FileInputStream in;
1018 try {
1019 in = file.openRead();
1020 } catch (FileNotFoundException e) {
1021 if (DEBUG) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001022 Slog.d(TAG, "Not found " + path);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001023 }
1024 return null;
1025 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001026 try {
Makoto Onukib08790c2016-06-23 14:05:46 -07001027 final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false);
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001028 return ret;
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07001029 } catch (IOException | XmlPullParserException | InvalidFileFormatException e) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001030 Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
1031 return null;
1032 } finally {
1033 IoUtils.closeQuietly(in);
1034 }
1035 }
1036
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001037 private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is,
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07001038 boolean fromBackup) throws XmlPullParserException, IOException,
1039 InvalidFileFormatException {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001040
1041 final BufferedInputStream bis = new BufferedInputStream(is);
1042
1043 ShortcutUser ret = null;
1044 XmlPullParser parser = Xml.newPullParser();
1045 parser.setInput(bis, StandardCharsets.UTF_8.name());
1046
1047 int type;
1048 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
1049 if (type != XmlPullParser.START_TAG) {
1050 continue;
1051 }
1052 final int depth = parser.getDepth();
1053
1054 final String tag = parser.getName();
1055 if (DEBUG_LOAD) {
1056 Slog.d(TAG, String.format("depth=%d type=%d name=%s",
1057 depth, type, tag));
1058 }
1059 if ((depth == 1) && ShortcutUser.TAG_ROOT.equals(tag)) {
1060 ret = ShortcutUser.loadFromXml(this, parser, userId, fromBackup);
1061 continue;
1062 }
1063 throwForInvalidTag(depth, tag);
1064 }
1065 return ret;
1066 }
1067
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001068 private void scheduleSaveBaseState() {
Makoto Onuki0acbb142016-03-22 17:02:57 -07001069 scheduleSaveInner(UserHandle.USER_NULL); // Special case -- use USER_NULL for base state.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001070 }
1071
Makoto Onuki2d5b4652016-03-11 16:09:54 -08001072 void scheduleSaveUser(@UserIdInt int userId) {
Makoto Onuki0acbb142016-03-22 17:02:57 -07001073 scheduleSaveInner(userId);
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001074 }
1075
1076 // In order to re-schedule, we need to reuse the same instance, so keep it in final.
1077 private final Runnable mSaveDirtyInfoRunner = this::saveDirtyInfo;
1078
Makoto Onuki0acbb142016-03-22 17:02:57 -07001079 private void scheduleSaveInner(@UserIdInt int userId) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001080 if (DEBUG) {
1081 Slog.d(TAG, "Scheduling to save for " + userId);
1082 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001083 synchronized (mLock) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001084 if (!mDirtyUserIds.contains(userId)) {
1085 mDirtyUserIds.add(userId);
1086 }
1087 }
1088 // If already scheduled, remove that and re-schedule in N seconds.
1089 mHandler.removeCallbacks(mSaveDirtyInfoRunner);
1090 mHandler.postDelayed(mSaveDirtyInfoRunner, mSaveDelayMillis);
1091 }
1092
1093 @VisibleForTesting
1094 void saveDirtyInfo() {
1095 if (DEBUG) {
1096 Slog.d(TAG, "saveDirtyInfo");
1097 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07001098 try {
1099 synchronized (mLock) {
1100 for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
1101 final int userId = mDirtyUserIds.get(i);
1102 if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
1103 saveBaseStateLocked();
1104 } else {
1105 saveUserLocked(userId);
1106 }
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001107 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07001108 mDirtyUserIds.clear();
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001109 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07001110 } catch (Exception e) {
1111 wtf("Exception in saveDirtyInfo", e);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001112 }
1113 }
1114
1115 /** Return the last reset time. */
1116 long getLastResetTimeLocked() {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001117 updateTimesLocked();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001118 return mRawLastResetTime;
1119 }
1120
1121 /** Return the next reset time. */
1122 long getNextResetTimeLocked() {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001123 updateTimesLocked();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001124 return mRawLastResetTime + mResetInterval;
1125 }
1126
Makoto Onuki4554d0e2016-03-14 15:51:41 -07001127 static boolean isClockValid(long time) {
1128 return time >= 1420070400; // Thu, 01 Jan 2015 00:00:00 GMT
1129 }
1130
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001131 /**
1132 * Update the last reset time.
1133 */
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001134 private void updateTimesLocked() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001135
1136 final long now = injectCurrentTimeMillis();
1137
1138 final long prevLastResetTime = mRawLastResetTime;
1139
1140 if (mRawLastResetTime == 0) { // first launch.
1141 // TODO Randomize??
1142 mRawLastResetTime = now;
1143 } else if (now < mRawLastResetTime) {
1144 // Clock rewound.
Makoto Onuki4554d0e2016-03-14 15:51:41 -07001145 if (isClockValid(now)) {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001146 Slog.w(TAG, "Clock rewound");
Makoto Onuki4554d0e2016-03-14 15:51:41 -07001147 // TODO Randomize??
1148 mRawLastResetTime = now;
1149 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001150 } else {
Makoto Onukiaa8b94a2016-03-17 13:14:05 -07001151 if ((mRawLastResetTime + mResetInterval) <= now) {
1152 final long offset = mRawLastResetTime % mResetInterval;
1153 mRawLastResetTime = ((now / mResetInterval) * mResetInterval) + offset;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001154 }
1155 }
1156 if (prevLastResetTime != mRawLastResetTime) {
1157 scheduleSaveBaseState();
1158 }
1159 }
1160
Makoto Onuki1e173232016-08-10 10:47:13 -07001161 // Requires mLock held, but "Locked" prefix would look weired so we just say "L".
Makoto Onuki02f338e2016-07-29 09:40:40 -07001162 protected boolean isUserUnlockedL(@UserIdInt int userId) {
Makoto Onuki1e173232016-08-10 10:47:13 -07001163 // First, check the local copy.
Makoto Onukie63b04a2017-12-11 14:47:19 -08001164 synchronized (mUnlockedUsers) {
1165 if (mUnlockedUsers.get(userId)) {
1166 return true;
1167 }
Makoto Onuki1e173232016-08-10 10:47:13 -07001168 }
Makoto Onukie63b04a2017-12-11 14:47:19 -08001169
Makoto Onuki1e173232016-08-10 10:47:13 -07001170 // If the local copy says the user is locked, check with AM for the actual state, since
1171 // the user might just have been unlocked.
1172 // Note we just don't use isUserUnlockingOrUnlocked() here, because it'll return false
1173 // when the user is STOPPING, which we still want to consider as "unlocked".
1174 final long token = injectClearCallingIdentity();
1175 try {
1176 return mUserManager.isUserUnlockingOrUnlocked(userId);
1177 } finally {
1178 injectRestoreCallingIdentity(token);
1179 }
Makoto Onuki9c850012016-07-26 15:50:50 -07001180 }
1181
Makoto Onuki02f338e2016-07-29 09:40:40 -07001182 // Requires mLock held, but "Locked" prefix would look weired so we jsut say "L".
1183 void throwIfUserLockedL(@UserIdInt int userId) {
1184 if (!isUserUnlockedL(userId)) {
Makoto Onuki9c850012016-07-26 15:50:50 -07001185 throw new IllegalStateException("User " + userId + " is locked or not running");
1186 }
1187 }
1188
Makoto Onukicdc78f72016-03-21 15:47:52 -07001189 @GuardedBy("mLock")
1190 @NonNull
Makoto Onuki2e210c42016-03-30 08:30:36 -07001191 private boolean isUserLoadedLocked(@UserIdInt int userId) {
Makoto Onukicdc78f72016-03-21 15:47:52 -07001192 return mUsers.get(userId) != null;
1193 }
1194
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001195 /** Return the per-user state. */
1196 @GuardedBy("mLock")
1197 @NonNull
Makoto Onuki31459242016-03-22 11:12:18 -07001198 ShortcutUser getUserShortcutsLocked(@UserIdInt int userId) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001199 if (!isUserUnlockedL(userId)) {
Makoto Onuki9c850012016-07-26 15:50:50 -07001200 wtf("User still locked");
Makoto Onuki9c850012016-07-26 15:50:50 -07001201 }
1202
Makoto Onuki31459242016-03-22 11:12:18 -07001203 ShortcutUser userPackages = mUsers.get(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001204 if (userPackages == null) {
1205 userPackages = loadUserLocked(userId);
1206 if (userPackages == null) {
Makoto Onukic51b2872016-05-04 15:24:50 -07001207 userPackages = new ShortcutUser(this, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001208 }
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -08001209 mUsers.put(userId, userPackages);
Makoto Onuki085a05c2016-08-19 11:39:29 -07001210
1211 // Also when a user's data is first accessed, scan all packages.
1212 checkPackageChanges(userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001213 }
1214 return userPackages;
1215 }
1216
Makoto Onuki708703b2017-12-11 16:38:11 -08001217 /** Return the non-persistent per-user state. */
1218 @GuardedBy("mLock")
1219 @NonNull
1220 ShortcutNonPersistentUser getNonPersistentUserLocked(@UserIdInt int userId) {
1221 ShortcutNonPersistentUser ret = mShortcutNonPersistentUsers.get(userId);
1222 if (ret == null) {
1223 ret = new ShortcutNonPersistentUser(this, userId);
1224 mShortcutNonPersistentUsers.put(userId, ret);
1225 }
1226 return ret;
1227 }
1228
Makoto Onuki2e210c42016-03-30 08:30:36 -07001229 void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
1230 for (int i = mUsers.size() - 1; i >= 0; i--) {
1231 c.accept(mUsers.valueAt(i));
1232 }
1233 }
1234
Makoto Onukic8c33292016-09-12 16:36:59 -07001235 /**
1236 * Return the per-user per-package state. If the caller is a publisher, use
1237 * {@link #getPackageShortcutsForPublisherLocked} instead.
1238 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001239 @GuardedBy("mLock")
1240 @NonNull
Makoto Onuki31459242016-03-22 11:12:18 -07001241 ShortcutPackage getPackageShortcutsLocked(
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001242 @NonNull String packageName, @UserIdInt int userId) {
Makoto Onukic51b2872016-05-04 15:24:50 -07001243 return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
Makoto Onukide667372016-03-15 14:29:20 -07001244 }
1245
Makoto Onukic8c33292016-09-12 16:36:59 -07001246 /** Return the per-user per-package state. Use this when the caller is a publisher. */
1247 @GuardedBy("mLock")
1248 @NonNull
1249 ShortcutPackage getPackageShortcutsForPublisherLocked(
1250 @NonNull String packageName, @UserIdInt int userId) {
1251 final ShortcutPackage ret = getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
1252 ret.getUser().onCalledByPublisher(packageName);
1253 return ret;
1254 }
1255
Makoto Onukide667372016-03-15 14:29:20 -07001256 @GuardedBy("mLock")
1257 @NonNull
Makoto Onuki2e210c42016-03-30 08:30:36 -07001258 ShortcutLauncher getLauncherShortcutsLocked(
1259 @NonNull String packageName, @UserIdInt int ownerUserId,
1260 @UserIdInt int launcherUserId) {
1261 return getUserShortcutsLocked(ownerUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07001262 .getLauncherShortcuts(packageName, launcherUserId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001263 }
1264
1265 // === Caller validation ===
1266
Makoto Onuki475c3652017-05-08 14:29:03 -07001267 void removeIconLocked(ShortcutInfo shortcut) {
1268 mShortcutBitmapSaver.removeIcon(shortcut);
Makoto Onuki55046222016-03-08 10:49:47 -08001269 }
1270
Makoto Onuki0033b2a2016-04-14 17:19:16 -07001271 public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) {
1272 final File packagePath = new File(getUserBitmapFilePath(userId), packageName);
1273 if (!packagePath.isDirectory()) {
1274 return;
1275 }
1276 if (!(FileUtils.deleteContents(packagePath) && packagePath.delete())) {
1277 Slog.w(TAG, "Unable to remove directory " + packagePath);
1278 }
1279 }
1280
Makoto Onuki475c3652017-05-08 14:29:03 -07001281 /**
1282 * Remove dangling bitmap files for a user.
1283 *
1284 * Note this method must be called with the lock held after calling
1285 * {@link ShortcutBitmapSaver#waitForAllSavesLocked()} to make sure there's no pending bitmap
1286 * saves are going on.
1287 */
Makoto Onuki1e173232016-08-10 10:47:13 -07001288 private void cleanupDanglingBitmapDirectoriesLocked(@UserIdInt int userId) {
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001289 if (DEBUG) {
1290 Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId);
1291 }
1292 final long start = injectElapsedRealtime();
1293
Makoto Onuki1e173232016-08-10 10:47:13 -07001294 final ShortcutUser user = getUserShortcutsLocked(userId);
1295
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001296 final File bitmapDir = getUserBitmapFilePath(userId);
1297 final File[] children = bitmapDir.listFiles();
1298 if (children == null) {
1299 return;
1300 }
1301 for (File child : children) {
1302 if (!child.isDirectory()) {
1303 continue;
1304 }
1305 final String packageName = child.getName();
1306 if (DEBUG) {
1307 Slog.d(TAG, "cleanupDanglingBitmaps: Found directory=" + packageName);
1308 }
1309 if (!user.hasPackage(packageName)) {
1310 if (DEBUG) {
1311 Slog.d(TAG, "Removing dangling bitmap directory: " + packageName);
1312 }
1313 cleanupBitmapsForPackage(userId, packageName);
1314 } else {
1315 cleanupDanglingBitmapFilesLocked(userId, user, packageName, child);
1316 }
1317 }
1318 logDurationStat(Stats.CLEANUP_DANGLING_BITMAPS, start);
1319 }
1320
Makoto Onuki475c3652017-05-08 14:29:03 -07001321 /**
1322 * Remove dangling bitmap files for a package.
1323 *
1324 * Note this method must be called with the lock held after calling
1325 * {@link ShortcutBitmapSaver#waitForAllSavesLocked()} to make sure there's no pending bitmap
1326 * saves are going on.
1327 */
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001328 private void cleanupDanglingBitmapFilesLocked(@UserIdInt int userId, @NonNull ShortcutUser user,
1329 @NonNull String packageName, @NonNull File path) {
1330 final ArraySet<String> usedFiles =
Makoto Onukic51b2872016-05-04 15:24:50 -07001331 user.getPackageShortcuts(packageName).getUsedBitmapFiles();
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07001332
1333 for (File child : path.listFiles()) {
1334 if (!child.isFile()) {
1335 continue;
1336 }
1337 final String name = child.getName();
1338 if (!usedFiles.contains(name)) {
1339 if (DEBUG) {
1340 Slog.d(TAG, "Removing dangling bitmap file: " + child.getAbsolutePath());
1341 }
1342 child.delete();
1343 }
1344 }
1345 }
1346
Makoto Onuki55046222016-03-08 10:49:47 -08001347 @VisibleForTesting
1348 static class FileOutputStreamWithPath extends FileOutputStream {
1349 private final File mFile;
1350
1351 public FileOutputStreamWithPath(File file) throws FileNotFoundException {
1352 super(file);
1353 mFile = file;
1354 }
1355
1356 public File getFile() {
1357 return mFile;
1358 }
1359 }
1360
1361 /**
1362 * Build the cached bitmap filename for a shortcut icon.
1363 *
1364 * The filename will be based on the ID, except certain characters will be escaped.
1365 */
Makoto Onuki55046222016-03-08 10:49:47 -08001366 FileOutputStreamWithPath openIconFileForWrite(@UserIdInt int userId, ShortcutInfo shortcut)
1367 throws IOException {
1368 final File packagePath = new File(getUserBitmapFilePath(userId),
Makoto Onuki22fcc682016-05-17 14:52:19 -07001369 shortcut.getPackage());
Makoto Onuki55046222016-03-08 10:49:47 -08001370 if (!packagePath.isDirectory()) {
1371 packagePath.mkdirs();
1372 if (!packagePath.isDirectory()) {
1373 throw new IOException("Unable to create directory " + packagePath);
1374 }
1375 SELinux.restorecon(packagePath);
1376 }
1377
1378 final String baseName = String.valueOf(injectCurrentTimeMillis());
Makoto Onukib08790c2016-06-23 14:05:46 -07001379 for (int suffix = 0; ; suffix++) {
Makoto Onuki55046222016-03-08 10:49:47 -08001380 final String filename = (suffix == 0 ? baseName : baseName + "_" + suffix) + ".png";
1381 final File file = new File(packagePath, filename);
1382 if (!file.exists()) {
1383 if (DEBUG) {
1384 Slog.d(TAG, "Saving icon to " + file.getAbsolutePath());
1385 }
1386 return new FileOutputStreamWithPath(file);
1387 }
1388 }
1389 }
1390
Makoto Onuki475c3652017-05-08 14:29:03 -07001391 void saveIconAndFixUpShortcutLocked(ShortcutInfo shortcut) {
Makoto Onuki55046222016-03-08 10:49:47 -08001392 if (shortcut.hasIconFile() || shortcut.hasIconResource()) {
1393 return;
1394 }
1395
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001396 final long token = injectClearCallingIdentity();
Makoto Onuki55046222016-03-08 10:49:47 -08001397 try {
1398 // Clear icon info on the shortcut.
Makoto Onuki475c3652017-05-08 14:29:03 -07001399 removeIconLocked(shortcut);
Makoto Onuki55046222016-03-08 10:49:47 -08001400
1401 final Icon icon = shortcut.getIcon();
1402 if (icon == null) {
1403 return; // has no icon
1404 }
Hyunyoung Song47037462017-05-08 16:51:43 -07001405 int maxIconDimension = mMaxIconDimension;
Makoto Onukiabe84422016-04-07 09:41:19 -07001406 Bitmap bitmap;
Makoto Onuki55046222016-03-08 10:49:47 -08001407 try {
1408 switch (icon.getType()) {
1409 case Icon.TYPE_RESOURCE: {
1410 injectValidateIconResPackage(shortcut, icon);
1411
1412 shortcut.setIconResourceId(icon.getResId());
1413 shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES);
1414 return;
1415 }
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001416 case Icon.TYPE_BITMAP:
Makoto Onukiabe84422016-04-07 09:41:19 -07001417 bitmap = icon.getBitmap(); // Don't recycle in this case.
Makoto Onuki55046222016-03-08 10:49:47 -08001418 break;
Hyunyoung Song47037462017-05-08 16:51:43 -07001419 case Icon.TYPE_ADAPTIVE_BITMAP: {
1420 bitmap = icon.getBitmap(); // Don't recycle in this case.
1421 maxIconDimension *= (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
Hyunyoung Song8947f592017-05-15 10:12:11 -07001422 break;
Makoto Onuki55046222016-03-08 10:49:47 -08001423 }
Makoto Onuki55046222016-03-08 10:49:47 -08001424 default:
1425 // This shouldn't happen because we've already validated the icon, but
1426 // just in case.
1427 throw ShortcutInfo.getInvalidIconException();
1428 }
Makoto Onuki475c3652017-05-08 14:29:03 -07001429 mShortcutBitmapSaver.saveBitmapLocked(shortcut,
Hyunyoung Song47037462017-05-08 16:51:43 -07001430 maxIconDimension, mIconPersistFormat, mIconPersistQuality);
Makoto Onuki55046222016-03-08 10:49:47 -08001431 } finally {
Makoto Onuki55046222016-03-08 10:49:47 -08001432 // Once saved, we won't use the original icon information, so null it out.
1433 shortcut.clearIcon();
1434 }
1435 } finally {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001436 injectRestoreCallingIdentity(token);
Makoto Onuki55046222016-03-08 10:49:47 -08001437 }
1438 }
1439
1440 // Unfortunately we can't do this check in unit tests because we fake creator package names,
1441 // so override in unit tests.
1442 // TODO CTS this case.
1443 void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07001444 if (!shortcut.getPackage().equals(icon.getResPackage())) {
Makoto Onuki55046222016-03-08 10:49:47 -08001445 throw new IllegalArgumentException(
1446 "Icon resource must reside in shortcut owner package");
1447 }
1448 }
1449
Makoto Onuki55046222016-03-08 10:49:47 -08001450 static Bitmap shrinkBitmap(Bitmap in, int maxSize) {
1451 // Original width/height.
1452 final int ow = in.getWidth();
1453 final int oh = in.getHeight();
1454 if ((ow <= maxSize) && (oh <= maxSize)) {
1455 if (DEBUG) {
1456 Slog.d(TAG, String.format("Icon size %dx%d, no need to shrink", ow, oh));
1457 }
1458 return in;
1459 }
1460 final int longerDimension = Math.max(ow, oh);
1461
1462 // New width and height.
1463 final int nw = ow * maxSize / longerDimension;
1464 final int nh = oh * maxSize / longerDimension;
1465 if (DEBUG) {
1466 Slog.d(TAG, String.format("Icon size %dx%d, shrinking to %dx%d",
1467 ow, oh, nw, nh));
1468 }
1469
1470 final Bitmap scaledBitmap = Bitmap.createBitmap(nw, nh, Bitmap.Config.ARGB_8888);
1471 final Canvas c = new Canvas(scaledBitmap);
1472
1473 final RectF dst = new RectF(0, 0, nw, nh);
1474
1475 c.drawBitmap(in, /*src=*/ null, dst, /* paint =*/ null);
1476
Makoto Onuki55046222016-03-08 10:49:47 -08001477 return scaledBitmap;
1478 }
1479
Makoto Onuki157b1622016-06-02 16:13:10 -07001480 /**
1481 * For a shortcut, update all resource names from resource IDs, and also update all
1482 * resource-based strings.
1483 */
1484 void fixUpShortcutResourceNamesAndValues(ShortcutInfo si) {
1485 final Resources publisherRes = injectGetResourcesForApplicationAsUser(
1486 si.getPackage(), si.getUserId());
1487 if (publisherRes != null) {
1488 final long start = injectElapsedRealtime();
1489 try {
1490 si.lookupAndFillInResourceNames(publisherRes);
1491 } finally {
1492 logDurationStat(Stats.RESOURCE_NAME_LOOKUP, start);
1493 }
1494 si.resolveResourceStrings(publisherRes);
1495 }
1496 }
1497
Makoto Onuki55046222016-03-08 10:49:47 -08001498 // === Caller validation ===
1499
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001500 private boolean isCallerSystem() {
1501 final int callingUid = injectBinderCallingUid();
Makoto Onukib08790c2016-06-23 14:05:46 -07001502 return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001503 }
1504
1505 private boolean isCallerShell() {
1506 final int callingUid = injectBinderCallingUid();
1507 return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
1508 }
1509
1510 private void enforceSystemOrShell() {
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07001511 if (!(isCallerSystem() || isCallerShell())) {
1512 throw new SecurityException("Caller must be system or shell");
1513 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001514 }
1515
1516 private void enforceShell() {
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07001517 if (!isCallerShell()) {
1518 throw new SecurityException("Caller must be shell");
1519 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001520 }
1521
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001522 private void enforceSystem() {
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07001523 if (!isCallerSystem()) {
1524 throw new SecurityException("Caller must be system");
1525 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -07001526 }
1527
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001528 private void enforceResetThrottlingPermission() {
1529 if (isCallerSystem()) {
1530 return;
1531 }
Makoto Onuki76269922016-07-15 14:58:54 -07001532 enforceCallingOrSelfPermission(
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001533 android.Manifest.permission.RESET_SHORTCUT_MANAGER_THROTTLING, null);
1534 }
1535
Makoto Onuki76269922016-07-15 14:58:54 -07001536 private void enforceCallingOrSelfPermission(
1537 @NonNull String permission, @Nullable String message) {
1538 if (isCallerSystem()) {
1539 return;
1540 }
1541 injectEnforceCallingPermission(permission, message);
1542 }
1543
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001544 /**
1545 * Somehow overriding ServiceContext.enforceCallingPermission() in the unit tests would confuse
1546 * mockito. So instead we extracted it here and override it in the tests.
1547 */
1548 @VisibleForTesting
1549 void injectEnforceCallingPermission(
1550 @NonNull String permission, @Nullable String message) {
1551 mContext.enforceCallingPermission(permission, message);
1552 }
1553
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001554 private void verifyCaller(@NonNull String packageName, @UserIdInt int userId) {
1555 Preconditions.checkStringNotEmpty(packageName, "packageName");
1556
1557 if (isCallerSystem()) {
1558 return; // no check
1559 }
1560
1561 final int callingUid = injectBinderCallingUid();
1562
1563 // Otherwise, make sure the arguments are valid.
1564 if (UserHandle.getUserId(callingUid) != userId) {
1565 throw new SecurityException("Invalid user-ID");
1566 }
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08001567 if (injectGetPackageUid(packageName, userId) != callingUid) {
1568 throw new SecurityException("Calling package name mismatch");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001569 }
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08001570 Preconditions.checkState(!isEphemeralApp(packageName, userId),
1571 "Ephemeral apps can't use ShortcutManager");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001572 }
1573
Makoto Onuki157b1622016-06-02 16:13:10 -07001574 // Overridden in unit tests to execute r synchronously.
1575 void injectPostToHandler(Runnable r) {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001576 mHandler.post(r);
1577 }
1578
Makoto Onuki085a05c2016-08-19 11:39:29 -07001579 void injectRunOnNewThread(Runnable r) {
1580 new Thread(r).start();
1581 }
1582
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001583 /**
Makoto Onuki7001a612016-05-27 13:24:28 -07001584 * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
Makoto Onukib08790c2016-06-23 14:05:46 -07001585 * {@link #getMaxActivityShortcuts()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001586 */
Makoto Onuki7001a612016-05-27 13:24:28 -07001587 void enforceMaxActivityShortcuts(int numShortcuts) {
Makoto Onukib5a012f2016-06-21 11:13:53 -07001588 if (numShortcuts > mMaxShortcuts) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001589 throw new IllegalArgumentException("Max number of dynamic shortcuts exceeded");
1590 }
1591 }
1592
1593 /**
Makoto Onuki7001a612016-05-27 13:24:28 -07001594 * Return the max number of dynamic + manifest shortcuts for each launcher icon.
1595 */
1596 int getMaxActivityShortcuts() {
Makoto Onukib5a012f2016-06-21 11:13:53 -07001597 return mMaxShortcuts;
Makoto Onuki7001a612016-05-27 13:24:28 -07001598 }
1599
1600 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001601 * - Sends a notification to LauncherApps
1602 * - Write to file
1603 */
Makoto Onuki39686e82016-04-13 18:03:00 -07001604 void packageShortcutsChanged(@NonNull String packageName, @UserIdInt int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001605 notifyListeners(packageName, userId);
1606 scheduleSaveUser(userId);
1607 }
1608
1609 private void notifyListeners(@NonNull String packageName, @UserIdInt int userId) {
Makoto Onuki82fb2eb2017-03-31 16:58:26 -07001610 if (DEBUG) {
1611 Slog.d(TAG, String.format(
1612 "Shortcut changes: package=%s, user=%d", packageName, userId));
1613 }
Makoto Onuki157b1622016-06-02 16:13:10 -07001614 injectPostToHandler(() -> {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001615 try {
1616 final ArrayList<ShortcutChangeListener> copy;
1617 synchronized (mLock) {
1618 if (!isUserUnlockedL(userId)) {
1619 return;
1620 }
1621
1622 copy = new ArrayList<>(mListeners);
1623 }
1624 // Note onShortcutChanged() needs to be called with the system service permissions.
1625 for (int i = copy.size() - 1; i >= 0; i--) {
1626 copy.get(i).onShortcutChanged(packageName, userId);
1627 }
1628 } catch (Exception ignore) {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001629 }
1630 });
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001631 }
1632
1633 /**
1634 * Clean up / validate an incoming shortcut.
1635 * - Make sure all mandatory fields are set.
1636 * - Make sure the intent's extras are persistable, and them to set
Makoto Onuki0eed4412016-07-21 11:21:59 -07001637 * {@link ShortcutInfo#mIntentPersistableExtrases}. Also clear its extras.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001638 * - Clear flags.
1639 */
Makoto Onuki2d895c32016-12-02 15:48:40 -08001640 private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate,
1641 boolean forPinRequest) {
Makoto Onukibf563b62017-05-04 10:25:30 -07001642 if (shortcut.isReturnedByServer()) {
1643 Log.w(TAG,
1644 "Re-publishing ShortcutInfo returned by server is not supported."
1645 + " Some information such as icon may lost from shortcut.");
1646 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001647 Preconditions.checkNotNull(shortcut, "Null shortcut detected");
Makoto Onuki255461f2017-01-10 11:47:25 -08001648 if (shortcut.getActivity() != null) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001649 Preconditions.checkState(
Makoto Onuki22fcc682016-05-17 14:52:19 -07001650 shortcut.getPackage().equals(shortcut.getActivity().getPackageName()),
Makoto Onukib08790c2016-06-23 14:05:46 -07001651 "Cannot publish shortcut: activity " + shortcut.getActivity() + " does not"
1652 + " belong to package " + shortcut.getPackage());
Makoto Onuki13260b6ff2016-07-13 18:03:13 -07001653 Preconditions.checkState(
1654 injectIsMainActivity(shortcut.getActivity(), shortcut.getUserId()),
1655 "Cannot publish shortcut: activity " + shortcut.getActivity() + " is not"
1656 + " main activity");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001657 }
1658
Makoto Onuki55046222016-03-08 10:49:47 -08001659 if (!forUpdate) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001660 shortcut.enforceMandatoryFields(/* forPinned= */ forPinRequest);
1661 if (!forPinRequest) {
Makoto Onuki255461f2017-01-10 11:47:25 -08001662 Preconditions.checkState(shortcut.getActivity() != null,
1663 "Cannot publish shortcut: target activity is not set");
Makoto Onuki2d895c32016-12-02 15:48:40 -08001664 }
Makoto Onuki55046222016-03-08 10:49:47 -08001665 }
1666 if (shortcut.getIcon() != null) {
1667 ShortcutInfo.validateIcon(shortcut.getIcon());
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001668 }
1669
Makoto Onukide667372016-03-15 14:29:20 -07001670 shortcut.replaceFlags(0);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001671 }
1672
Makoto Onuki2d895c32016-12-02 15:48:40 -08001673 private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
1674 fixUpIncomingShortcutInfo(shortcut, forUpdate, /*forPinRequest=*/ false);
1675 }
1676
1677 public void validateShortcutForPinRequest(@NonNull ShortcutInfo shortcut) {
1678 fixUpIncomingShortcutInfo(shortcut, /* forUpdate= */ false, /*forPinRequest=*/ true);
1679 }
1680
Makoto Onukib08790c2016-06-23 14:05:46 -07001681 /**
1682 * When a shortcut has no target activity, set the default one from the package.
1683 */
1684 private void fillInDefaultActivity(List<ShortcutInfo> shortcuts) {
Makoto Onukib08790c2016-06-23 14:05:46 -07001685 ComponentName defaultActivity = null;
1686 for (int i = shortcuts.size() - 1; i >= 0; i--) {
1687 final ShortcutInfo si = shortcuts.get(i);
1688 if (si.getActivity() == null) {
1689 if (defaultActivity == null) {
1690 defaultActivity = injectGetDefaultMainActivity(
1691 si.getPackage(), si.getUserId());
1692 Preconditions.checkState(defaultActivity != null,
1693 "Launcher activity not found for package " + si.getPackage());
1694 }
1695 si.setActivity(defaultActivity);
1696 }
1697 }
1698 }
1699
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001700 private void assignImplicitRanks(List<ShortcutInfo> shortcuts) {
1701 for (int i = shortcuts.size() - 1; i >= 0; i--) {
1702 shortcuts.get(i).setImplicitRank(i);
1703 }
1704 }
1705
Makoto Onukibf563b62017-05-04 10:25:30 -07001706 private List<ShortcutInfo> setReturnedByServer(List<ShortcutInfo> shortcuts) {
1707 for (int i = shortcuts.size() - 1; i >= 0; i--) {
1708 shortcuts.get(i).setReturnedByServer();
1709 }
1710 return shortcuts;
1711 }
1712
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001713 // === APIs ===
1714
1715 @Override
1716 public boolean setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
1717 @UserIdInt int userId) {
1718 verifyCaller(packageName, userId);
1719
1720 final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
1721 final int size = newShortcuts.size();
1722
1723 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001724 throwIfUserLockedL(userId);
1725
Makoto Onukic8c33292016-09-12 16:36:59 -07001726 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001727
Makoto Onukia4f89b12017-10-05 10:37:55 -07001728 ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001729
Makoto Onukib08790c2016-06-23 14:05:46 -07001730 fillInDefaultActivity(newShortcuts);
1731
Makoto Onuki7001a612016-05-27 13:24:28 -07001732 ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_SET);
1733
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001734 // Throttling.
Makoto Onukic51b2872016-05-04 15:24:50 -07001735 if (!ps.tryApiCall()) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001736 return false;
1737 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001738
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001739 // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
1740 ps.clearAllImplicitRanks();
1741 assignImplicitRanks(newShortcuts);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001742
Makoto Onukidf6da042016-06-16 09:51:40 -07001743 for (int i = 0; i < size; i++) {
1744 fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false);
1745 }
1746
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001747 // First, remove all un-pinned; dynamic shortcuts
Makoto Onukia4f89b12017-10-05 10:37:55 -07001748 ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001749
1750 // Then, add/update all. We need to make sure to take over "pinned" flag.
1751 for (int i = 0; i < size; i++) {
1752 final ShortcutInfo newShortcut = newShortcuts.get(i);
Makoto Onukia4f89b12017-10-05 10:37:55 -07001753 ps.addOrReplaceDynamicShortcut(newShortcut);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001754 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001755
1756 // Lastly, adjust the ranks.
1757 ps.adjustRanks();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001758 }
Makoto Onuki39686e82016-04-13 18:03:00 -07001759 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07001760
1761 verifyStates();
1762
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001763 return true;
1764 }
1765
1766 @Override
1767 public boolean updateShortcuts(String packageName, ParceledListSlice shortcutInfoList,
1768 @UserIdInt int userId) {
1769 verifyCaller(packageName, userId);
1770
1771 final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
Makoto Onuki55046222016-03-08 10:49:47 -08001772 final int size = newShortcuts.size();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001773
1774 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001775 throwIfUserLockedL(userId);
1776
Makoto Onukic8c33292016-09-12 16:36:59 -07001777 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001778
Makoto Onukia4f89b12017-10-05 10:37:55 -07001779 ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001780
Makoto Onukib08790c2016-06-23 14:05:46 -07001781 // For update, don't fill in the default activity. Having null activity means
1782 // "don't update the activity" here.
1783
Makoto Onuki7001a612016-05-27 13:24:28 -07001784 ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_UPDATE);
1785
Makoto Onuki55046222016-03-08 10:49:47 -08001786 // Throttling.
Makoto Onukic51b2872016-05-04 15:24:50 -07001787 if (!ps.tryApiCall()) {
Makoto Onuki55046222016-03-08 10:49:47 -08001788 return false;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001789 }
1790
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001791 // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
1792 ps.clearAllImplicitRanks();
1793 assignImplicitRanks(newShortcuts);
1794
Makoto Onuki55046222016-03-08 10:49:47 -08001795 for (int i = 0; i < size; i++) {
1796 final ShortcutInfo source = newShortcuts.get(i);
1797 fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
1798
1799 final ShortcutInfo target = ps.findShortcutById(source.getId());
Makoto Onukia4f89b12017-10-05 10:37:55 -07001800
1801 // Invisible shortcuts can't be updated.
1802 if (target == null || !target.isVisibleToPublisher()) {
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001803 continue;
1804 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07001805
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001806 if (target.isEnabled() != source.isEnabled()) {
1807 Slog.w(TAG,
1808 "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
1809 }
Makoto Onuki55046222016-03-08 10:49:47 -08001810
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001811 // When updating the rank, we need to insert between existing ranks, so set
1812 // this setRankChanged, and also copy the implicit rank fo adjustRanks().
1813 if (source.hasRank()) {
1814 target.setRankChanged();
1815 target.setImplicitRank(source.getImplicitRank());
1816 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07001817
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001818 final boolean replacingIcon = (source.getIcon() != null);
1819 if (replacingIcon) {
Makoto Onuki475c3652017-05-08 14:29:03 -07001820 removeIconLocked(target);
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001821 }
Makoto Onuki55046222016-03-08 10:49:47 -08001822
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001823 // Note copyNonNullFieldsFrom() does the "updatable with?" check too.
1824 target.copyNonNullFieldsFrom(source);
1825 target.setTimestamp(injectCurrentTimeMillis());
1826
1827 if (replacingIcon) {
Makoto Onuki475c3652017-05-08 14:29:03 -07001828 saveIconAndFixUpShortcutLocked(target);
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001829 }
1830
1831 // When we're updating any resource related fields, re-extract the res names and
1832 // the values.
1833 if (replacingIcon || source.hasStringResources()) {
1834 fixUpShortcutResourceNamesAndValues(target);
Makoto Onuki55046222016-03-08 10:49:47 -08001835 }
1836 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001837
1838 // Lastly, adjust the ranks.
1839 ps.adjustRanks();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001840 }
Makoto Onuki39686e82016-04-13 18:03:00 -07001841 packageShortcutsChanged(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001842
Makoto Onuki7001a612016-05-27 13:24:28 -07001843 verifyStates();
1844
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001845 return true;
1846 }
1847
1848 @Override
Makoto Onukia4f89b12017-10-05 10:37:55 -07001849 public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001850 @UserIdInt int userId) {
1851 verifyCaller(packageName, userId);
1852
Makoto Onukib6d35232016-04-04 15:57:17 -07001853 final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
1854 final int size = newShortcuts.size();
1855
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001856 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001857 throwIfUserLockedL(userId);
1858
Makoto Onukic8c33292016-09-12 16:36:59 -07001859 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001860
Makoto Onukia4f89b12017-10-05 10:37:55 -07001861 ps.ensureImmutableShortcutsNotIncluded(newShortcuts, /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001862
Makoto Onukib08790c2016-06-23 14:05:46 -07001863 fillInDefaultActivity(newShortcuts);
1864
Makoto Onuki7001a612016-05-27 13:24:28 -07001865 ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_ADD);
1866
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001867 // Initialize the implicit ranks for ShortcutPackage.adjustRanks().
1868 ps.clearAllImplicitRanks();
1869 assignImplicitRanks(newShortcuts);
1870
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001871 // Throttling.
Makoto Onukic51b2872016-05-04 15:24:50 -07001872 if (!ps.tryApiCall()) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001873 return false;
1874 }
Makoto Onukib6d35232016-04-04 15:57:17 -07001875 for (int i = 0; i < size; i++) {
1876 final ShortcutInfo newShortcut = newShortcuts.get(i);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001877
Makoto Onukib6d35232016-04-04 15:57:17 -07001878 // Validate the shortcut.
1879 fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001880
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001881 // When ranks are changing, we need to insert between ranks, so set the
1882 // "rank changed" flag.
1883 newShortcut.setRankChanged();
1884
Makoto Onukib6d35232016-04-04 15:57:17 -07001885 // Add it.
Makoto Onukia4f89b12017-10-05 10:37:55 -07001886 ps.addOrReplaceDynamicShortcut(newShortcut);
Makoto Onukib6d35232016-04-04 15:57:17 -07001887 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001888
1889 // Lastly, adjust the ranks.
1890 ps.adjustRanks();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001891 }
Makoto Onuki39686e82016-04-13 18:03:00 -07001892 packageShortcutsChanged(packageName, userId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001893
Makoto Onuki7001a612016-05-27 13:24:28 -07001894 verifyStates();
1895
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001896 return true;
1897 }
1898
1899 @Override
Makoto Onuki2d895c32016-12-02 15:48:40 -08001900 public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
1901 IntentSender resultIntent, int userId) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001902 Preconditions.checkNotNull(shortcut);
1903 Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001904 return requestPinItem(packageName, userId, shortcut, null, null, resultIntent);
Sunny Goyal87a563e2017-01-01 19:42:45 -08001905 }
1906
Sunny Goyala6be88a2017-01-12 16:27:58 -08001907 @Override
1908 public Intent createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId)
1909 throws RemoteException {
1910 Preconditions.checkNotNull(shortcut);
1911 Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
1912 verifyCaller(packageName, userId);
1913
1914 final Intent ret;
1915 synchronized (mLock) {
1916 throwIfUserLockedL(userId);
1917
1918 // Send request to the launcher, if supported.
1919 ret = mShortcutRequestPinProcessor.createShortcutResultIntent(shortcut, userId);
1920 }
1921
1922 verifyStates();
1923 return ret;
1924 }
1925
Sunny Goyal87a563e2017-01-01 19:42:45 -08001926 /**
1927 * Handles {@link #requestPinShortcut} and {@link ShortcutServiceInternal#requestPinAppWidget}.
1928 * After validating the caller, it passes the request to {@link #mShortcutRequestPinProcessor}.
1929 * Either {@param shortcut} or {@param appWidget} should be non-null.
1930 */
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001931 private boolean requestPinItem(String packageName, int userId, ShortcutInfo shortcut,
1932 AppWidgetProviderInfo appWidget, Bundle extras, IntentSender resultIntent) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08001933 verifyCaller(packageName, userId);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001934
1935 final boolean ret;
1936 synchronized (mLock) {
1937 throwIfUserLockedL(userId);
1938
Makoto Onukia01f4f02016-12-15 15:58:41 -08001939 Preconditions.checkState(isUidForegroundLocked(injectBinderCallingUid()),
Makoto Onuki255461f2017-01-10 11:47:25 -08001940 "Calling application must have a foreground activity or a foreground service");
Makoto Onuki2d895c32016-12-02 15:48:40 -08001941
Makoto Onukia4f89b12017-10-05 10:37:55 -07001942 // If it's a pin shortcut request, and there's already a shortcut with the same ID
1943 // that's not visible to the caller (i.e. restore-blocked; meaning it's pinned by
1944 // someone already), then we just replace the existing one with this new one,
1945 // and then proceed the rest of the process.
1946 if (shortcut != null) {
1947 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(
1948 packageName, userId);
1949 final String id = shortcut.getId();
1950 if (ps.isShortcutExistsAndInvisibleToPublisher(id)) {
1951
1952 ps.updateInvisibleShortcutForPinRequestWith(shortcut);
1953
1954 packageShortcutsChanged(packageName, userId);
1955 }
1956 }
1957
Makoto Onuki2d895c32016-12-02 15:48:40 -08001958 // Send request to the launcher, if supported.
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001959 ret = mShortcutRequestPinProcessor.requestPinItemLocked(shortcut, appWidget, extras,
1960 userId, resultIntent);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001961 }
1962
1963 verifyStates();
1964
1965 return ret;
1966 }
1967
1968 @Override
Makoto Onuki20c95f82016-05-11 16:51:01 -07001969 public void disableShortcuts(String packageName, List shortcutIds,
Makoto Onukid6880792016-06-29 13:37:43 -07001970 CharSequence disabledMessage, int disabledMessageResId, @UserIdInt int userId) {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001971 verifyCaller(packageName, userId);
1972 Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
1973
1974 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07001975 throwIfUserLockedL(userId);
1976
Makoto Onukic8c33292016-09-12 16:36:59 -07001977 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001978
Makoto Onukia4f89b12017-10-05 10:37:55 -07001979 ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
1980 /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001981
Makoto Onukid6880792016-06-29 13:37:43 -07001982 final String disabledMessageString =
1983 (disabledMessage == null) ? null : disabledMessage.toString();
1984
Makoto Onuki22fcc682016-05-17 14:52:19 -07001985 for (int i = shortcutIds.size() - 1; i >= 0; i--) {
Makoto Onukia4f89b12017-10-05 10:37:55 -07001986 final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
1987 if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
1988 continue;
1989 }
1990 ps.disableWithId(id,
Makoto Onukid6880792016-06-29 13:37:43 -07001991 disabledMessageString, disabledMessageResId,
Makoto Onukia4f89b12017-10-05 10:37:55 -07001992 /* overrideImmutable=*/ false, /*ignoreInvisible=*/ true,
1993 ShortcutInfo.DISABLED_REASON_BY_APP);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001994 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001995
1996 // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
1997 ps.adjustRanks();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001998 }
1999 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002000
2001 verifyStates();
Makoto Onuki22fcc682016-05-17 14:52:19 -07002002 }
2003
2004 @Override
2005 public void enableShortcuts(String packageName, List shortcutIds, @UserIdInt int userId) {
2006 verifyCaller(packageName, userId);
2007 Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
2008
2009 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002010 throwIfUserLockedL(userId);
2011
Makoto Onukic8c33292016-09-12 16:36:59 -07002012 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002013
Makoto Onukia4f89b12017-10-05 10:37:55 -07002014 ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
2015 /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002016
2017 for (int i = shortcutIds.size() - 1; i >= 0; i--) {
Makoto Onukia4f89b12017-10-05 10:37:55 -07002018 final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
2019 if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
2020 continue;
2021 }
2022 ps.enableWithId(id);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002023 }
Makoto Onuki20c95f82016-05-11 16:51:01 -07002024 }
2025 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002026
2027 verifyStates();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002028 }
2029
2030 @Override
Makoto Onukib6d35232016-04-04 15:57:17 -07002031 public void removeDynamicShortcuts(String packageName, List shortcutIds,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002032 @UserIdInt int userId) {
2033 verifyCaller(packageName, userId);
Makoto Onukib6d35232016-04-04 15:57:17 -07002034 Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002035
2036 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002037 throwIfUserLockedL(userId);
2038
Makoto Onukic8c33292016-09-12 16:36:59 -07002039 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002040
Makoto Onukia4f89b12017-10-05 10:37:55 -07002041 ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds,
2042 /*ignoreInvisible=*/ true);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002043
Makoto Onukib6d35232016-04-04 15:57:17 -07002044 for (int i = shortcutIds.size() - 1; i >= 0; i--) {
Makoto Onukia4f89b12017-10-05 10:37:55 -07002045 final String id = Preconditions.checkStringNotEmpty((String) shortcutIds.get(i));
2046 if (!ps.isShortcutExistsAndVisibleToPublisher(id)) {
2047 continue;
2048 }
2049 ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true);
Makoto Onukib6d35232016-04-04 15:57:17 -07002050 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07002051
2052 // We may have removed dynamic shortcuts which may have left a gap, so adjust the ranks.
2053 ps.adjustRanks();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002054 }
Makoto Onuki39686e82016-04-13 18:03:00 -07002055 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002056
2057 verifyStates();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002058 }
2059
2060 @Override
Makoto Onukib6d35232016-04-04 15:57:17 -07002061 public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002062 verifyCaller(packageName, userId);
2063
2064 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002065 throwIfUserLockedL(userId);
2066
Makoto Onukic8c33292016-09-12 16:36:59 -07002067 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onukia4f89b12017-10-05 10:37:55 -07002068 ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002069 }
Makoto Onuki39686e82016-04-13 18:03:00 -07002070 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002071
2072 verifyStates();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002073 }
2074
2075 @Override
2076 public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName,
2077 @UserIdInt int userId) {
2078 verifyCaller(packageName, userId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002079
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002080 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002081 throwIfUserLockedL(userId);
2082
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002083 return getShortcutsWithQueryLocked(
2084 packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
Makoto Onukia4f89b12017-10-05 10:37:55 -07002085 ShortcutInfo::isDynamicVisible);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002086 }
2087 }
2088
2089 @Override
Makoto Onuki22fcc682016-05-17 14:52:19 -07002090 public ParceledListSlice<ShortcutInfo> getManifestShortcuts(String packageName,
2091 @UserIdInt int userId) {
2092 verifyCaller(packageName, userId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002093
Makoto Onuki22fcc682016-05-17 14:52:19 -07002094 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002095 throwIfUserLockedL(userId);
2096
Makoto Onuki22fcc682016-05-17 14:52:19 -07002097 return getShortcutsWithQueryLocked(
2098 packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
Makoto Onukia4f89b12017-10-05 10:37:55 -07002099 ShortcutInfo::isManifestVisible);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002100 }
2101 }
2102
2103 @Override
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002104 public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName,
2105 @UserIdInt int userId) {
2106 verifyCaller(packageName, userId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002107
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002108 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002109 throwIfUserLockedL(userId);
2110
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002111 return getShortcutsWithQueryLocked(
2112 packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
Makoto Onukia4f89b12017-10-05 10:37:55 -07002113 ShortcutInfo::isPinnedVisible);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002114 }
2115 }
2116
2117 private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
2118 @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
2119
2120 final ArrayList<ShortcutInfo> ret = new ArrayList<>();
2121
Makoto Onukic8c33292016-09-12 16:36:59 -07002122 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002123 ps.findAll(ret, query, cloneFlags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002124
Makoto Onukibf563b62017-05-04 10:25:30 -07002125 return new ParceledListSlice<>(setReturnedByServer(ret));
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002126 }
2127
2128 @Override
Makoto Onukid6880792016-06-29 13:37:43 -07002129 public int getMaxShortcutCountPerActivity(String packageName, @UserIdInt int userId)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002130 throws RemoteException {
2131 verifyCaller(packageName, userId);
2132
Makoto Onukib5a012f2016-06-21 11:13:53 -07002133 return mMaxShortcuts;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002134 }
2135
2136 @Override
2137 public int getRemainingCallCount(String packageName, @UserIdInt int userId) {
2138 verifyCaller(packageName, userId);
2139
2140 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002141 throwIfUserLockedL(userId);
2142
Makoto Onukic8c33292016-09-12 16:36:59 -07002143 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002144 return mMaxUpdatesPerInterval - ps.getApiCallCount();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002145 }
2146 }
2147
2148 @Override
2149 public long getRateLimitResetTime(String packageName, @UserIdInt int userId) {
2150 verifyCaller(packageName, userId);
2151
2152 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002153 throwIfUserLockedL(userId);
2154
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002155 return getNextResetTimeLocked();
2156 }
2157 }
2158
Makoto Onuki55046222016-03-08 10:49:47 -08002159 @Override
Makoto Onuki20c95f82016-05-11 16:51:01 -07002160 public int getIconMaxDimensions(String packageName, int userId) {
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07002161 verifyCaller(packageName, userId);
2162
Makoto Onuki55046222016-03-08 10:49:47 -08002163 synchronized (mLock) {
2164 return mMaxIconDimension;
2165 }
2166 }
2167
Makoto Onuki20c95f82016-05-11 16:51:01 -07002168 @Override
2169 public void reportShortcutUsed(String packageName, String shortcutId, int userId) {
2170 verifyCaller(packageName, userId);
2171
Makoto Onukiac042502016-05-20 16:39:42 -07002172 Preconditions.checkNotNull(shortcutId);
2173
2174 if (DEBUG) {
2175 Slog.d(TAG, String.format("reportShortcutUsed: Shortcut %s package %s used on user %d",
2176 shortcutId, packageName, userId));
2177 }
2178
2179 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002180 throwIfUserLockedL(userId);
2181
Makoto Onukic8c33292016-09-12 16:36:59 -07002182 final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002183
Makoto Onukiac042502016-05-20 16:39:42 -07002184 if (ps.findShortcutById(shortcutId) == null) {
2185 Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
2186 packageName, shortcutId));
2187 return;
2188 }
2189 }
2190
2191 final long token = injectClearCallingIdentity();
2192 try {
2193 mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId);
2194 } finally {
2195 injectRestoreCallingIdentity(token);
2196 }
Makoto Onuki20c95f82016-05-11 16:51:01 -07002197 }
2198
Makoto Onuki2d895c32016-12-02 15:48:40 -08002199 @Override
Sunny Goyal7f7372a2017-01-24 11:53:54 -08002200 public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08002201 final long token = injectClearCallingIdentity();
2202 try {
Sunny Goyal7f7372a2017-01-24 11:53:54 -08002203 return mShortcutRequestPinProcessor
2204 .isRequestPinItemSupported(callingUserId, requestType);
Makoto Onuki2d895c32016-12-02 15:48:40 -08002205 } finally {
2206 injectRestoreCallingIdentity(token);
2207 }
2208 }
2209
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002210 /**
Makoto Onukib08790c2016-06-23 14:05:46 -07002211 * Reset all throttling, for developer options and command line. Only system/shell can call
2212 * it.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002213 */
2214 @Override
2215 public void resetThrottling() {
2216 enforceSystemOrShell();
2217
Makoto Onuki4554d0e2016-03-14 15:51:41 -07002218 resetThrottlingInner(getCallingUserId());
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002219 }
2220
Makoto Onuki4554d0e2016-03-14 15:51:41 -07002221 void resetThrottlingInner(@UserIdInt int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002222 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002223 if (!isUserUnlockedL(userId)) {
2224 Log.w(TAG, "User " + userId + " is locked or not running");
2225 return;
2226 }
2227
Makoto Onuki4554d0e2016-03-14 15:51:41 -07002228 getUserShortcutsLocked(userId).resetThrottling();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002229 }
Makoto Onuki4554d0e2016-03-14 15:51:41 -07002230 scheduleSaveUser(userId);
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07002231 Slog.i(TAG, "ShortcutManager: throttling counter reset for user " + userId);
2232 }
2233
2234 void resetAllThrottlingInner() {
2235 synchronized (mLock) {
2236 mRawLastResetTime = injectCurrentTimeMillis();
2237 }
2238 scheduleSaveBaseState();
2239 Slog.i(TAG, "ShortcutManager: throttling counter reset for all users");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002240 }
2241
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002242 @Override
2243 public void onApplicationActive(String packageName, int userId) {
2244 if (DEBUG) {
2245 Slog.d(TAG, "onApplicationActive: package=" + packageName + " userid=" + userId);
2246 }
2247 enforceResetThrottlingPermission();
Makoto Onuki02f338e2016-07-29 09:40:40 -07002248
2249 synchronized (mLock) {
2250 if (!isUserUnlockedL(userId)) {
2251 // This is called by system UI, so no need to throw. Just ignore.
2252 return;
2253 }
2254
2255 getPackageShortcutsLocked(packageName, userId)
2256 .resetRateLimitingForCommandLineNoSaving();
2257 saveUserLocked(userId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002258 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002259 }
2260
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002261 // We override this method in unit tests to do a simpler check.
Makoto Onuki634cecb2017-10-13 17:10:48 -07002262 boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId,
2263 int callingPid, int callingUid) {
Makoto Onuki35559d62017-11-06 16:26:32 -08002264 if (canSeeAnyPinnedShortcut(callingPackage, userId, callingPid, callingUid)) {
Makoto Onuki634cecb2017-10-13 17:10:48 -07002265 return true;
2266 }
Makoto Onuki10305202016-07-14 18:14:08 -07002267 final long start = injectElapsedRealtime();
2268 try {
2269 return hasShortcutHostPermissionInner(callingPackage, userId);
2270 } finally {
2271 logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start);
2272 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002273 }
2274
Makoto Onuki35559d62017-11-06 16:26:32 -08002275 boolean canSeeAnyPinnedShortcut(@NonNull String callingPackage, int userId,
2276 int callingPid, int callingUid) {
2277 if (injectHasAccessShortcutsPermission(callingPid, callingUid)) {
2278 return true;
2279 }
2280 synchronized (mLock) {
Makoto Onuki708703b2017-12-11 16:38:11 -08002281 return getNonPersistentUserLocked(userId).hasHostPackage(callingPackage);
Makoto Onuki35559d62017-11-06 16:26:32 -08002282 }
2283 }
2284
Makoto Onuki634cecb2017-10-13 17:10:48 -07002285 /**
2286 * Returns true if the caller has the "ACCESS_SHORTCUTS" permission.
2287 */
Makoto Onuki35559d62017-11-06 16:26:32 -08002288 @VisibleForTesting
2289 boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
Makoto Onuki634cecb2017-10-13 17:10:48 -07002290 return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS,
2291 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
2292 }
2293
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002294 // This method is extracted so we can directly call this method from unit tests,
2295 // even when hasShortcutPermission() is overridden.
2296 @VisibleForTesting
Makoto Onuki2d895c32016-12-02 15:48:40 -08002297 boolean hasShortcutHostPermissionInner(@NonNull String packageName, int userId) {
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002298 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002299 throwIfUserLockedL(userId);
2300
Makoto Onuki31459242016-03-22 11:12:18 -07002301 final ShortcutUser user = getUserShortcutsLocked(userId);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002302
Makoto Onuki2d895c32016-12-02 15:48:40 -08002303 // Always trust the cached component.
Makoto Onuki10305202016-07-14 18:14:08 -07002304 final ComponentName cached = user.getCachedLauncher();
2305 if (cached != null) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08002306 if (cached.getPackageName().equals(packageName)) {
Makoto Onuki10305202016-07-14 18:14:08 -07002307 return true;
2308 }
2309 }
2310 // If the cached one doesn't match, then go ahead
2311
Makoto Onuki2d895c32016-12-02 15:48:40 -08002312 final ComponentName detected = getDefaultLauncher(userId);
Makoto Onuki2e210c42016-03-30 08:30:36 -07002313
Makoto Onuki10305202016-07-14 18:14:08 -07002314 // Update the cache.
2315 user.setLauncher(detected);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002316 if (detected != null) {
2317 if (DEBUG) {
2318 Slog.v(TAG, "Detected launcher: " + detected);
2319 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08002320 return detected.getPackageName().equals(packageName);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002321 } else {
2322 // Default launcher not found.
2323 return false;
2324 }
2325 }
2326 }
2327
Makoto Onuki2d895c32016-12-02 15:48:40 -08002328 @Nullable
2329 ComponentName getDefaultLauncher(@UserIdInt int userId) {
2330 final long start = injectElapsedRealtime();
2331 final long token = injectClearCallingIdentity();
2332 try {
2333 synchronized (mLock) {
2334 throwIfUserLockedL(userId);
2335
2336 final ShortcutUser user = getUserShortcutsLocked(userId);
2337
2338 final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
2339
2340 // Default launcher from package manager.
2341 final long startGetHomeActivitiesAsUser = injectElapsedRealtime();
2342 final ComponentName defaultLauncher = mPackageManagerInternal
2343 .getHomeActivitiesAsUser(allHomeCandidates, userId);
2344 logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
2345
2346 ComponentName detected = null;
2347 if (defaultLauncher != null) {
2348 detected = defaultLauncher;
2349 if (DEBUG) {
2350 Slog.v(TAG, "Default launcher from PM: " + detected);
2351 }
2352 } else {
2353 detected = user.getLastKnownLauncher();
2354
2355 if (detected != null) {
2356 if (injectIsActivityEnabledAndExported(detected, userId)) {
2357 if (DEBUG) {
2358 Slog.v(TAG, "Cached launcher: " + detected);
2359 }
2360 } else {
2361 Slog.w(TAG, "Cached launcher " + detected + " no longer exists");
2362 detected = null;
2363 user.clearLauncher();
2364 }
2365 }
2366 }
2367
2368 if (detected == null) {
2369 // If we reach here, that means it's the first check since the user was created,
2370 // and there's already multiple launchers and there's no default set.
2371 // Find the system one with the highest priority.
2372 // (We need to check the priority too because of FallbackHome in Settings.)
2373 // If there's no system launcher yet, then no one can access shortcuts, until
2374 // the user explicitly
2375 final int size = allHomeCandidates.size();
2376
2377 int lastPriority = Integer.MIN_VALUE;
2378 for (int i = 0; i < size; i++) {
2379 final ResolveInfo ri = allHomeCandidates.get(i);
2380 if (!ri.activityInfo.applicationInfo.isSystemApp()) {
2381 continue;
2382 }
2383 if (DEBUG) {
2384 Slog.d(TAG, String.format("hasShortcutPermissionInner: pkg=%s prio=%d",
2385 ri.activityInfo.getComponentName(), ri.priority));
2386 }
2387 if (ri.priority < lastPriority) {
2388 continue;
2389 }
2390 detected = ri.activityInfo.getComponentName();
2391 lastPriority = ri.priority;
2392 }
2393 }
2394 return detected;
2395 }
2396 } finally {
2397 injectRestoreCallingIdentity(token);
2398 logDurationStat(Stats.GET_DEFAULT_LAUNCHER, start);
2399 }
2400 }
2401
Dianne Hackbornc160fa42017-11-01 16:14:26 -07002402 public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
2403 int userId) {
2404 synchronized (mLock) {
Makoto Onuki708703b2017-12-11 16:38:11 -08002405 getNonPersistentUserLocked(userId).setShortcutHostPackage(type, packageName);
Dianne Hackbornc160fa42017-11-01 16:14:26 -07002406 }
2407 }
2408
Makoto Onukicdc78f72016-03-21 15:47:52 -07002409 // === House keeping ===
2410
Makoto Onukib08790c2016-06-23 14:05:46 -07002411 private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
2412 boolean appStillExists) {
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002413 synchronized (mLock) {
2414 forEachLoadedUserLocked(user ->
Makoto Onukib08790c2016-06-23 14:05:46 -07002415 cleanUpPackageLocked(packageName, user.getUserId(), packageUserId,
2416 appStillExists));
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002417 }
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07002418 }
2419
Makoto Onuki2e210c42016-03-30 08:30:36 -07002420 /**
2421 * Remove all the information associated with a package. This will really remove all the
2422 * information, including the restore information (i.e. it'll remove packages even if they're
2423 * shadow).
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002424 *
2425 * This is called when an app is uninstalled, or an app gets "clear data"ed.
Makoto Onuki2e210c42016-03-30 08:30:36 -07002426 */
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002427 @VisibleForTesting
Makoto Onukib08790c2016-06-23 14:05:46 -07002428 void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId,
2429 boolean appStillExists) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002430 final boolean wasUserLoaded = isUserLoadedLocked(owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002431
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002432 final ShortcutUser user = getUserShortcutsLocked(owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002433 boolean doNotify = false;
2434
2435 // First, remove the package from the package list (if the package is a publisher).
Makoto Onukid99c6f02016-03-28 11:02:54 -07002436 if (packageUserId == owningUserId) {
Makoto Onukic51b2872016-05-04 15:24:50 -07002437 if (user.removePackage(packageName) != null) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002438 doNotify = true;
2439 }
Makoto Onukicdc78f72016-03-21 15:47:52 -07002440 }
Makoto Onukid99c6f02016-03-28 11:02:54 -07002441
Makoto Onukicdc78f72016-03-21 15:47:52 -07002442 // Also remove from the launcher list (if the package is a launcher).
Makoto Onuki9ac59d02016-04-26 11:23:14 -07002443 user.removeLauncher(packageUserId, packageName);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002444
2445 // Then remove pinned shortcuts from all launchers.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002446 user.forAllLaunchers(l -> l.cleanUpPackage(packageName, packageUserId));
2447
2448 // Now there may be orphan shortcuts because we removed pinned shortcuts at the previous
Makoto Onukicdc78f72016-03-21 15:47:52 -07002449 // step. Remove them too.
Makoto Onukic51b2872016-05-04 15:24:50 -07002450 user.forAllPackages(p -> p.refreshPinnedFlags());
Makoto Onukicdc78f72016-03-21 15:47:52 -07002451
Makoto Onukid99c6f02016-03-28 11:02:54 -07002452 scheduleSaveUser(owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002453
2454 if (doNotify) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002455 notifyListeners(packageName, owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002456 }
2457
Makoto Onukib08790c2016-06-23 14:05:46 -07002458 // If the app still exists (i.e. data cleared), we need to re-publish manifest shortcuts.
2459 if (appStillExists && (packageUserId == owningUserId)) {
2460 // This will do the notification and save when needed, so do it after the above
2461 // notifyListeners.
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002462 user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
Makoto Onukib08790c2016-06-23 14:05:46 -07002463 }
2464
Makoto Onukicdc78f72016-03-21 15:47:52 -07002465 if (!wasUserLoaded) {
2466 // Note this will execute the scheduled save.
Makoto Onukid99c6f02016-03-28 11:02:54 -07002467 unloadUserLocked(owningUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002468 }
2469 }
2470
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002471 /**
2472 * Entry point from {@link LauncherApps}.
2473 */
2474 private class LocalService extends ShortcutServiceInternal {
Makoto Onuki2e210c42016-03-30 08:30:36 -07002475
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002476 @Override
Makoto Onukid99c6f02016-03-28 11:02:54 -07002477 public List<ShortcutInfo> getShortcuts(int launcherUserId,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002478 @NonNull String callingPackage, long changedSince,
Makoto Onukiabe84422016-04-07 09:41:19 -07002479 @Nullable String packageName, @Nullable List<String> shortcutIds,
Makoto Onuki99302b52017-03-29 12:42:26 -07002480 @Nullable ComponentName componentName,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002481 int queryFlags, int userId, int callingPid, int callingUid) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002482 final ArrayList<ShortcutInfo> ret = new ArrayList<>();
Makoto Onuki9c850012016-07-26 15:50:50 -07002483
Makoto Onuki20c95f82016-05-11 16:51:01 -07002484 final boolean cloneKeyFieldOnly =
2485 ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
2486 final int cloneFlag = cloneKeyFieldOnly ? ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO
2487 : ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER;
Makoto Onukiabe84422016-04-07 09:41:19 -07002488 if (packageName == null) {
2489 shortcutIds = null; // LauncherAppsService already threw for it though.
2490 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002491
2492 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002493 throwIfUserLockedL(userId);
2494 throwIfUserLockedL(launcherUserId);
2495
Makoto Onuki2e210c42016-03-30 08:30:36 -07002496 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002497 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002498
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002499 if (packageName != null) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002500 getShortcutsInnerLocked(launcherUserId,
Makoto Onukiabe84422016-04-07 09:41:19 -07002501 callingPackage, packageName, shortcutIds, changedSince,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002502 componentName, queryFlags, userId, ret, cloneFlag,
2503 callingPid, callingUid);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002504 } else {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002505 final List<String> shortcutIdsF = shortcutIds;
2506 getUserShortcutsLocked(userId).forAllPackages(p -> {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002507 getShortcutsInnerLocked(launcherUserId,
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002508 callingPackage, p.getPackageName(), shortcutIdsF, changedSince,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002509 componentName, queryFlags, userId, ret, cloneFlag,
2510 callingPid, callingUid);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002511 });
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002512 }
2513 }
Makoto Onukibf563b62017-05-04 10:25:30 -07002514 return setReturnedByServer(ret);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002515 }
2516
Makoto Onukid99c6f02016-03-28 11:02:54 -07002517 private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
Makoto Onukiabe84422016-04-07 09:41:19 -07002518 @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
Makoto Onuki99302b52017-03-29 12:42:26 -07002519 @Nullable ComponentName componentName, int queryFlags,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002520 int userId, ArrayList<ShortcutInfo> ret, int cloneFlag,
2521 int callingPid, int callingUid) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002522 final ArraySet<String> ids = shortcutIds == null ? null
2523 : new ArraySet<>(shortcutIds);
2524
Makoto Onuki35559d62017-11-06 16:26:32 -08002525 final ShortcutUser user = getUserShortcutsLocked(userId);
2526 final ShortcutPackage p = user.getPackageShortcutsIfExists(packageName);
Makoto Onukic51b2872016-05-04 15:24:50 -07002527 if (p == null) {
2528 return; // No need to instantiate ShortcutPackage.
2529 }
Makoto Onuki634cecb2017-10-13 17:10:48 -07002530 final boolean matchDynamic = (queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0;
2531 final boolean matchPinned = (queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
2532 final boolean matchManifest = (queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
2533
Makoto Onuki35559d62017-11-06 16:26:32 -08002534 final boolean canAccessAllShortcuts =
2535 canSeeAnyPinnedShortcut(callingPackage, launcherUserId, callingPid, callingUid);
2536
Makoto Onuki634cecb2017-10-13 17:10:48 -07002537 final boolean getPinnedByAnyLauncher =
Makoto Onuki35559d62017-11-06 16:26:32 -08002538 canAccessAllShortcuts &&
2539 ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER) != 0);
Makoto Onukic51b2872016-05-04 15:24:50 -07002540
2541 p.findAll(ret,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002542 (ShortcutInfo si) -> {
2543 if (si.getLastChangedTimestamp() < changedSince) {
2544 return false;
2545 }
Makoto Onukiabe84422016-04-07 09:41:19 -07002546 if (ids != null && !ids.contains(si.getId())) {
2547 return false;
2548 }
Makoto Onuki85694522016-05-04 12:53:37 -07002549 if (componentName != null) {
Makoto Onuki9fd90192017-01-06 18:31:03 +00002550 if (si.getActivity() != null
2551 && !si.getActivity().equals(componentName)) {
Makoto Onuki85694522016-05-04 12:53:37 -07002552 return false;
2553 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002554 }
Makoto Onuki634cecb2017-10-13 17:10:48 -07002555 if (matchDynamic && si.isDynamic()) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002556 return true;
2557 }
Makoto Onuki35559d62017-11-06 16:26:32 -08002558 if ((matchPinned || getPinnedByAnyLauncher) && si.isPinned()) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002559 return true;
2560 }
Makoto Onuki634cecb2017-10-13 17:10:48 -07002561 if (matchManifest && si.isDeclaredInManifest()) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002562 return true;
2563 }
2564 return false;
Makoto Onuki634cecb2017-10-13 17:10:48 -07002565 }, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002566 }
2567
2568 @Override
Makoto Onukid99c6f02016-03-28 11:02:54 -07002569 public boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
2570 @NonNull String packageName, @NonNull String shortcutId, int userId) {
2571 Preconditions.checkStringNotEmpty(packageName, "packageName");
2572 Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
2573
2574 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002575 throwIfUserLockedL(userId);
2576 throwIfUserLockedL(launcherUserId);
2577
Makoto Onuki2e210c42016-03-30 08:30:36 -07002578 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002579 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002580
Makoto Onukid99c6f02016-03-28 11:02:54 -07002581 final ShortcutInfo si = getShortcutInfoLocked(
Makoto Onuki634cecb2017-10-13 17:10:48 -07002582 launcherUserId, callingPackage, packageName, shortcutId, userId,
2583 /*getPinnedByAnyLauncher=*/ false);
Makoto Onukid99c6f02016-03-28 11:02:54 -07002584 return si != null && si.isPinned();
2585 }
2586 }
2587
Makoto Onuki2e210c42016-03-30 08:30:36 -07002588 private ShortcutInfo getShortcutInfoLocked(
Makoto Onukid99c6f02016-03-28 11:02:54 -07002589 int launcherUserId, @NonNull String callingPackage,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002590 @NonNull String packageName, @NonNull String shortcutId, int userId,
2591 boolean getPinnedByAnyLauncher) {
Makoto Onukid99c6f02016-03-28 11:02:54 -07002592 Preconditions.checkStringNotEmpty(packageName, "packageName");
2593 Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
2594
Makoto Onuki02f338e2016-07-29 09:40:40 -07002595 throwIfUserLockedL(userId);
2596 throwIfUserLockedL(launcherUserId);
Makoto Onuki9c850012016-07-26 15:50:50 -07002597
Makoto Onukic51b2872016-05-04 15:24:50 -07002598 final ShortcutPackage p = getUserShortcutsLocked(userId)
2599 .getPackageShortcutsIfExists(packageName);
2600 if (p == null) {
2601 return null;
2602 }
2603
Makoto Onukid99c6f02016-03-28 11:02:54 -07002604 final ArrayList<ShortcutInfo> list = new ArrayList<>(1);
Makoto Onukic51b2872016-05-04 15:24:50 -07002605 p.findAll(list,
Makoto Onukid99c6f02016-03-28 11:02:54 -07002606 (ShortcutInfo si) -> shortcutId.equals(si.getId()),
Makoto Onuki634cecb2017-10-13 17:10:48 -07002607 /* clone flags=*/ 0, callingPackage, launcherUserId, getPinnedByAnyLauncher);
Makoto Onukid99c6f02016-03-28 11:02:54 -07002608 return list.size() == 0 ? null : list.get(0);
2609 }
2610
2611 @Override
2612 public void pinShortcuts(int launcherUserId,
2613 @NonNull String callingPackage, @NonNull String packageName,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002614 @NonNull List<String> shortcutIds, int userId) {
2615 // Calling permission must be checked by LauncherAppsImpl.
2616 Preconditions.checkStringNotEmpty(packageName, "packageName");
2617 Preconditions.checkNotNull(shortcutIds, "shortcutIds");
2618
2619 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002620 throwIfUserLockedL(userId);
2621 throwIfUserLockedL(launcherUserId);
2622
Makoto Onuki9da23fc2016-03-29 11:14:42 -07002623 final ShortcutLauncher launcher =
Makoto Onuki2e210c42016-03-30 08:30:36 -07002624 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
Makoto Onukic51b2872016-05-04 15:24:50 -07002625 launcher.attemptToRestoreIfNeededAndSave();
Makoto Onuki9da23fc2016-03-29 11:14:42 -07002626
Makoto Onukia4f89b12017-10-05 10:37:55 -07002627 launcher.pinShortcuts(userId, packageName, shortcutIds, /*forPinRequest=*/ false);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002628 }
Makoto Onuki39686e82016-04-13 18:03:00 -07002629 packageShortcutsChanged(packageName, userId);
Makoto Onuki7001a612016-05-27 13:24:28 -07002630
2631 verifyStates();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002632 }
2633
2634 @Override
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002635 public Intent[] createShortcutIntents(int launcherUserId,
Makoto Onukid99c6f02016-03-28 11:02:54 -07002636 @NonNull String callingPackage,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002637 @NonNull String packageName, @NonNull String shortcutId, int userId,
2638 int callingPid, int callingUid) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002639 // Calling permission must be checked by LauncherAppsImpl.
Makoto Onuki43204b82016-03-08 16:16:44 -08002640 Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
2641 Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002642
2643 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002644 throwIfUserLockedL(userId);
2645 throwIfUserLockedL(launcherUserId);
2646
Makoto Onuki2e210c42016-03-30 08:30:36 -07002647 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002648 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002649
Makoto Onuki634cecb2017-10-13 17:10:48 -07002650 final boolean getPinnedByAnyLauncher =
Makoto Onuki35559d62017-11-06 16:26:32 -08002651 canSeeAnyPinnedShortcut(callingPackage, launcherUserId,
2652 callingPid, callingUid);
Makoto Onuki634cecb2017-10-13 17:10:48 -07002653
Makoto Onukid99c6f02016-03-28 11:02:54 -07002654 // Make sure the shortcut is actually visible to the launcher.
2655 final ShortcutInfo si = getShortcutInfoLocked(
Makoto Onuki634cecb2017-10-13 17:10:48 -07002656 launcherUserId, callingPackage, packageName, shortcutId, userId,
2657 getPinnedByAnyLauncher);
Makoto Onukid99c6f02016-03-28 11:02:54 -07002658 // "si == null" should suffice here, but check the flags too just to make sure.
Makoto Onuki35559d62017-11-06 16:26:32 -08002659 if (si == null || !si.isEnabled() || !(si.isAlive() || getPinnedByAnyLauncher)) {
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07002660 Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
Makoto Onukid99c6f02016-03-28 11:02:54 -07002661 return null;
2662 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002663 return si.getIntents();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002664 }
2665 }
2666
2667 @Override
2668 public void addListener(@NonNull ShortcutChangeListener listener) {
2669 synchronized (mLock) {
2670 mListeners.add(Preconditions.checkNotNull(listener));
2671 }
2672 }
Makoto Onuki55046222016-03-08 10:49:47 -08002673
2674 @Override
Makoto Onukiabe84422016-04-07 09:41:19 -07002675 public int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
2676 @NonNull String packageName, @NonNull String shortcutId, int userId) {
2677 Preconditions.checkNotNull(callingPackage, "callingPackage");
2678 Preconditions.checkNotNull(packageName, "packageName");
2679 Preconditions.checkNotNull(shortcutId, "shortcutId");
Makoto Onuki55046222016-03-08 10:49:47 -08002680
2681 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002682 throwIfUserLockedL(userId);
2683 throwIfUserLockedL(launcherUserId);
2684
Makoto Onuki2e210c42016-03-30 08:30:36 -07002685 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002686 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002687
Makoto Onukic51b2872016-05-04 15:24:50 -07002688 final ShortcutPackage p = getUserShortcutsLocked(userId)
2689 .getPackageShortcutsIfExists(packageName);
2690 if (p == null) {
2691 return 0;
2692 }
2693
2694 final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
Makoto Onuki55046222016-03-08 10:49:47 -08002695 return (shortcutInfo != null && shortcutInfo.hasIconResource())
2696 ? shortcutInfo.getIconResourceId() : 0;
2697 }
2698 }
2699
2700 @Override
Makoto Onukid99c6f02016-03-28 11:02:54 -07002701 public ParcelFileDescriptor getShortcutIconFd(int launcherUserId,
Makoto Onukiabe84422016-04-07 09:41:19 -07002702 @NonNull String callingPackage, @NonNull String packageName,
2703 @NonNull String shortcutId, int userId) {
2704 Preconditions.checkNotNull(callingPackage, "callingPackage");
2705 Preconditions.checkNotNull(packageName, "packageName");
2706 Preconditions.checkNotNull(shortcutId, "shortcutId");
Makoto Onuki55046222016-03-08 10:49:47 -08002707
2708 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002709 throwIfUserLockedL(userId);
2710 throwIfUserLockedL(launcherUserId);
2711
Makoto Onuki2e210c42016-03-30 08:30:36 -07002712 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
Makoto Onukic51b2872016-05-04 15:24:50 -07002713 .attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -07002714
Makoto Onukic51b2872016-05-04 15:24:50 -07002715 final ShortcutPackage p = getUserShortcutsLocked(userId)
2716 .getPackageShortcutsIfExists(packageName);
2717 if (p == null) {
2718 return null;
2719 }
2720
2721 final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
Makoto Onuki55046222016-03-08 10:49:47 -08002722 if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
2723 return null;
2724 }
Makoto Onuki475c3652017-05-08 14:29:03 -07002725 final String path = mShortcutBitmapSaver.getBitmapPathMayWaitLocked(shortcutInfo);
2726 if (path == null) {
2727 Slog.w(TAG, "null bitmap detected in getShortcutIconFd()");
2728 return null;
2729 }
Makoto Onuki55046222016-03-08 10:49:47 -08002730 try {
2731 return ParcelFileDescriptor.open(
Makoto Onuki475c3652017-05-08 14:29:03 -07002732 new File(path),
Makoto Onuki55046222016-03-08 10:49:47 -08002733 ParcelFileDescriptor.MODE_READ_ONLY);
2734 } catch (FileNotFoundException e) {
Makoto Onuki475c3652017-05-08 14:29:03 -07002735 Slog.e(TAG, "Icon file not found: " + path);
Makoto Onuki55046222016-03-08 10:49:47 -08002736 return null;
2737 }
2738 }
2739 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002740
2741 @Override
Makoto Onukid99c6f02016-03-28 11:02:54 -07002742 public boolean hasShortcutHostPermission(int launcherUserId,
Makoto Onuki634cecb2017-10-13 17:10:48 -07002743 @NonNull String callingPackage, int callingPid, int callingUid) {
2744 return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId,
2745 callingPid, callingUid);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08002746 }
Sunny Goyal87a563e2017-01-01 19:42:45 -08002747
2748 @Override
Dianne Hackbornc160fa42017-11-01 16:14:26 -07002749 public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
2750 int userId) {
2751 ShortcutService.this.setShortcutHostPackage(type, packageName, userId);
2752 }
2753
2754 @Override
Sunny Goyal87a563e2017-01-01 19:42:45 -08002755 public boolean requestPinAppWidget(@NonNull String callingPackage,
Sunny Goyal4ad6b572017-02-28 11:11:51 -08002756 @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
2757 @Nullable IntentSender resultIntent, int userId) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08002758 Preconditions.checkNotNull(appWidget);
Sunny Goyal4ad6b572017-02-28 11:11:51 -08002759 return requestPinItem(callingPackage, userId, null, appWidget, extras, resultIntent);
Sunny Goyal87a563e2017-01-01 19:42:45 -08002760 }
Sunny Goyal7f7372a2017-01-24 11:53:54 -08002761
2762 @Override
2763 public boolean isRequestPinItemSupported(int callingUserId, int requestType) {
2764 return ShortcutService.this.isRequestPinItemSupported(callingUserId, requestType);
2765 }
Tony Maked6ef622017-12-07 16:36:16 +00002766
2767 @Override
2768 public boolean isForegroundDefaultLauncher(@NonNull String callingPackage, int callingUid) {
2769 Preconditions.checkNotNull(callingPackage);
2770
2771 final int userId = UserHandle.getUserId(callingUid);
2772 final ComponentName defaultLauncher = getDefaultLauncher(userId);
2773 if (defaultLauncher == null) {
2774 return false;
2775 }
2776 if (!callingPackage.equals(defaultLauncher.getPackageName())) {
2777 return false;
2778 }
2779 synchronized (mLock) {
2780 if (!isUidForegroundLocked(callingUid)) {
2781 return false;
2782 }
2783 }
2784 return true;
2785 }
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002786 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002787
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002788 final BroadcastReceiver mReceiver = new BroadcastReceiver() {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002789 @Override
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002790 public void onReceive(Context context, Intent intent) {
2791 if (!mBootCompleted.get()) {
2792 return; // Boot not completed, ignore the broadcast.
2793 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07002794 try {
2795 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
2796 handleLocaleChanged();
2797 }
2798 } catch (Exception e) {
2799 wtf("Exception in mReceiver.onReceive", e);
Makoto Onukic51b2872016-05-04 15:24:50 -07002800 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07002801 }
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002802 };
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002803
Makoto Onuki157b1622016-06-02 16:13:10 -07002804 void handleLocaleChanged() {
2805 if (DEBUG) {
2806 Slog.d(TAG, "handleLocaleChanged");
2807 }
2808 scheduleSaveBaseState();
2809
Makoto Onuki02f338e2016-07-29 09:40:40 -07002810 synchronized (mLock) {
2811 final long token = injectClearCallingIdentity();
2812 try {
2813 forEachLoadedUserLocked(user -> user.detectLocaleChange());
2814 } finally {
2815 injectRestoreCallingIdentity(token);
2816 }
Makoto Onuki157b1622016-06-02 16:13:10 -07002817 }
2818 }
2819
Makoto Onukif34c3082016-07-13 10:25:25 -07002820 /**
2821 * Package event callbacks.
2822 */
2823 @VisibleForTesting
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002824 final BroadcastReceiver mPackageMonitor = new BroadcastReceiver() {
Makoto Onukif34c3082016-07-13 10:25:25 -07002825 @Override
2826 public void onReceive(Context context, Intent intent) {
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002827 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
2828 if (userId == UserHandle.USER_NULL) {
2829 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
2830 return;
2831 }
2832
2833 final String action = intent.getAction();
2834
2835 // This is normally called on Handler, so clearCallingIdentity() isn't needed,
2836 // but we still check it in unit tests.
Makoto Onukif34c3082016-07-13 10:25:25 -07002837 final long token = injectClearCallingIdentity();
2838 try {
Makoto Onuki10305202016-07-14 18:14:08 -07002839 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07002840 if (!isUserUnlockedL(userId)) {
2841 if (DEBUG) {
2842 Slog.d(TAG, "Ignoring package broadcast " + action
2843 + " for locked/stopped user " + userId);
2844 }
2845 return;
2846 }
2847
2848 // Whenever we get one of those package broadcasts, or get
2849 // ACTION_PREFERRED_ACTIVITY_CHANGED, we purge the default launcher cache.
Makoto Onuki10305202016-07-14 18:14:08 -07002850 final ShortcutUser user = getUserShortcutsLocked(userId);
2851 user.clearLauncher();
2852 }
2853 if (Intent.ACTION_PREFERRED_ACTIVITY_CHANGED.equals(action)) {
2854 // Nothing farther to do.
2855 return;
2856 }
2857
Makoto Onuki4e6cef42016-07-13 16:14:01 -07002858 final Uri intentUri = intent.getData();
2859 final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart()
2860 : null;
2861 if (packageName == null) {
2862 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
2863 return;
2864 }
2865
2866 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
2867
2868 switch (action) {
2869 case Intent.ACTION_PACKAGE_ADDED:
2870 if (replacing) {
2871 handlePackageUpdateFinished(packageName, userId);
2872 } else {
2873 handlePackageAdded(packageName, userId);
2874 }
2875 break;
2876 case Intent.ACTION_PACKAGE_REMOVED:
2877 if (!replacing) {
2878 handlePackageRemoved(packageName, userId);
2879 }
2880 break;
2881 case Intent.ACTION_PACKAGE_CHANGED:
2882 handlePackageChanged(packageName, userId);
2883
2884 break;
2885 case Intent.ACTION_PACKAGE_DATA_CLEARED:
2886 handlePackageDataCleared(packageName, userId);
2887 break;
2888 }
Makoto Onuki02f338e2016-07-29 09:40:40 -07002889 } catch (Exception e) {
2890 wtf("Exception in mPackageMonitor.onReceive", e);
Makoto Onukif34c3082016-07-13 10:25:25 -07002891 } finally {
2892 injectRestoreCallingIdentity(token);
Makoto Onukia2241832016-07-06 13:28:37 -07002893 }
Makoto Onukicdc78f72016-03-21 15:47:52 -07002894 }
Makoto Onukif34c3082016-07-13 10:25:25 -07002895 };
Makoto Onukicdc78f72016-03-21 15:47:52 -07002896
Makoto Onuki0acbb142016-03-22 17:02:57 -07002897 /**
Makoto Onuki39686e82016-04-13 18:03:00 -07002898 * Called when a user is unlocked.
2899 * - Check all known packages still exist, and otherwise perform cleanup.
2900 * - If a package still exists, check the version code. If it's been updated, may need to
Makoto Onukib08790c2016-06-23 14:05:46 -07002901 * update timestamps of its shortcuts.
Makoto Onuki0acbb142016-03-22 17:02:57 -07002902 */
Makoto Onukid99c6f02016-03-28 11:02:54 -07002903 @VisibleForTesting
Makoto Onuki39686e82016-04-13 18:03:00 -07002904 void checkPackageChanges(@UserIdInt int ownerUserId) {
Makoto Onukicdc78f72016-03-21 15:47:52 -07002905 if (DEBUG) {
Makoto Onuki39686e82016-04-13 18:03:00 -07002906 Slog.d(TAG, "checkPackageChanges() ownerUserId=" + ownerUserId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07002907 }
Makoto Onukib08790c2016-06-23 14:05:46 -07002908 if (injectIsSafeModeEnabled()) {
2909 Slog.i(TAG, "Safe mode, skipping checkPackageChanges()");
2910 return;
2911 }
Makoto Onuki0acbb142016-03-22 17:02:57 -07002912
Makoto Onuki22fcc682016-05-17 14:52:19 -07002913 final long start = injectElapsedRealtime();
2914 try {
2915 final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
Makoto Onuki9da23fc2016-03-29 11:14:42 -07002916
Makoto Onuki22fcc682016-05-17 14:52:19 -07002917 synchronized (mLock) {
2918 final ShortcutUser user = getUserShortcutsLocked(ownerUserId);
2919
2920 // Find packages that have been uninstalled.
2921 user.forAllPackageItems(spi -> {
2922 if (spi.getPackageInfo().isShadow()) {
2923 return; // Don't delete shadow information.
2924 }
2925 if (!isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07002926 if (DEBUG) {
2927 Slog.d(TAG, "Uninstalled: " + spi.getPackageName()
2928 + " user " + spi.getPackageUserId());
2929 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002930 gonePackages.add(PackageWithUser.of(spi));
2931 }
2932 });
2933 if (gonePackages.size() > 0) {
2934 for (int i = gonePackages.size() - 1; i >= 0; i--) {
2935 final PackageWithUser pu = gonePackages.get(i);
Makoto Onukib08790c2016-06-23 14:05:46 -07002936 cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId,
2937 /* appStillExists = */ false);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002938 }
Makoto Onukid99c6f02016-03-28 11:02:54 -07002939 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002940
Makoto Onuki248a0ef2016-11-03 15:59:01 -07002941 rescanUpdatedPackagesLocked(ownerUserId, user.getLastAppScanTime());
Makoto Onuki0acbb142016-03-22 17:02:57 -07002942 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002943 } finally {
2944 logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start);
Makoto Onuki0acbb142016-03-22 17:02:57 -07002945 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07002946 verifyStates();
Makoto Onukicdc78f72016-03-21 15:47:52 -07002947 }
2948
Makoto Onuki248a0ef2016-11-03 15:59:01 -07002949 private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime) {
Makoto Onuki377b7972016-08-09 14:43:55 -07002950 final ShortcutUser user = getUserShortcutsLocked(userId);
2951
Makoto Onuki33663282016-08-22 16:19:04 -07002952 // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
2953 // is not reliable.
Makoto Onuki377b7972016-08-09 14:43:55 -07002954 final long now = injectCurrentTimeMillis();
Makoto Onuki33663282016-08-22 16:19:04 -07002955 final boolean afterOta =
2956 !injectBuildFingerprint().equals(user.getLastAppScanOsFingerprint());
Makoto Onuki377b7972016-08-09 14:43:55 -07002957
2958 // Then for each installed app, publish manifest shortcuts when needed.
Makoto Onuki33663282016-08-22 16:19:04 -07002959 forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
Makoto Onuki377b7972016-08-09 14:43:55 -07002960 user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
Makoto Onuki248a0ef2016-11-03 15:59:01 -07002961
2962 user.rescanPackageIfNeeded(ai.packageName, /* forceRescan= */ true);
Makoto Onuki377b7972016-08-09 14:43:55 -07002963 });
2964
2965 // Write the time just before the scan, because there may be apps that have just
2966 // been updated, and we want to catch them in the next time.
2967 user.setLastAppScanTime(now);
Makoto Onuki33663282016-08-22 16:19:04 -07002968 user.setLastAppScanOsFingerprint(injectBuildFingerprint());
Makoto Onuki377b7972016-08-09 14:43:55 -07002969 scheduleSaveUser(userId);
2970 }
2971
Makoto Onuki0acbb142016-03-22 17:02:57 -07002972 private void handlePackageAdded(String packageName, @UserIdInt int userId) {
Makoto Onukicdc78f72016-03-21 15:47:52 -07002973 if (DEBUG) {
Makoto Onuki0acbb142016-03-22 17:02:57 -07002974 Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
2975 }
2976 synchronized (mLock) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002977 final ShortcutUser user = getUserShortcutsLocked(userId);
2978 user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
Makoto Onuki64183d52016-08-08 14:11:34 -07002979 user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
Makoto Onuki0acbb142016-03-22 17:02:57 -07002980 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07002981 verifyStates();
Makoto Onuki0acbb142016-03-22 17:02:57 -07002982 }
2983
2984 private void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
Makoto Onuki905e8852016-03-28 10:40:58 -07002985 if (DEBUG) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07002986 Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d",
2987 packageName, userId));
Makoto Onuki0acbb142016-03-22 17:02:57 -07002988 }
2989 synchronized (mLock) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07002990 final ShortcutUser user = getUserShortcutsLocked(userId);
2991 user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
Makoto Onuki39686e82016-04-13 18:03:00 -07002992
Makoto Onuki22fcc682016-05-17 14:52:19 -07002993 if (isPackageInstalled(packageName, userId)) {
Makoto Onuki64183d52016-08-08 14:11:34 -07002994 user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
Makoto Onuki39686e82016-04-13 18:03:00 -07002995 }
Makoto Onuki0acbb142016-03-22 17:02:57 -07002996 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07002997 verifyStates();
Makoto Onuki0acbb142016-03-22 17:02:57 -07002998 }
2999
Makoto Onuki2e210c42016-03-30 08:30:36 -07003000 private void handlePackageRemoved(String packageName, @UserIdInt int packageUserId) {
Makoto Onuki0acbb142016-03-22 17:02:57 -07003001 if (DEBUG) {
Makoto Onuki2e210c42016-03-30 08:30:36 -07003002 Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName,
3003 packageUserId));
Makoto Onukicdc78f72016-03-21 15:47:52 -07003004 }
Makoto Onukib08790c2016-06-23 14:05:46 -07003005 cleanUpPackageForAllLoadedUsers(packageName, packageUserId, /* appStillExists = */ false);
Makoto Onuki9e1f5592016-06-08 12:30:23 -07003006
3007 verifyStates();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07003008 }
3009
Makoto Onuki9ac59d02016-04-26 11:23:14 -07003010 private void handlePackageDataCleared(String packageName, int packageUserId) {
3011 if (DEBUG) {
3012 Slog.d(TAG, String.format("handlePackageDataCleared: %s user=%d", packageName,
3013 packageUserId));
Makoto Onukicdc78f72016-03-21 15:47:52 -07003014 }
Makoto Onukib08790c2016-06-23 14:05:46 -07003015 cleanUpPackageForAllLoadedUsers(packageName, packageUserId, /* appStillExists = */ true);
3016
3017 verifyStates();
3018 }
3019
3020 private void handlePackageChanged(String packageName, int packageUserId) {
Makoto Onuki82fb2eb2017-03-31 16:58:26 -07003021 if (!isPackageInstalled(packageName, packageUserId)) {
3022 // Probably disabled, which is the same thing as uninstalled.
3023 handlePackageRemoved(packageName, packageUserId);
3024 return;
3025 }
Makoto Onukib08790c2016-06-23 14:05:46 -07003026 if (DEBUG) {
3027 Slog.d(TAG, String.format("handlePackageChanged: %s user=%d", packageName,
3028 packageUserId));
3029 }
3030
3031 // Activities may be disabled or enabled. Just rescan the package.
3032 synchronized (mLock) {
3033 final ShortcutUser user = getUserShortcutsLocked(packageUserId);
3034
Makoto Onuki4e6cef42016-07-13 16:14:01 -07003035 user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
Makoto Onukib08790c2016-06-23 14:05:46 -07003036 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -07003037
3038 verifyStates();
Makoto Onukicdc78f72016-03-21 15:47:52 -07003039 }
3040
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003041 // === PackageManager interaction ===
Makoto Onuki0acbb142016-03-22 17:02:57 -07003042
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003043 /**
3044 * Returns {@link PackageInfo} unless it's uninstalled or disabled.
3045 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003046 @Nullable
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003047 final PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) {
3048 return getPackageInfo(packageName, userId, true);
Makoto Onuki0acbb142016-03-22 17:02:57 -07003049 }
3050
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003051 /**
3052 * Returns {@link PackageInfo} unless it's uninstalled or disabled.
3053 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003054 @Nullable
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003055 final PackageInfo getPackageInfo(String packageName, @UserIdInt int userId) {
3056 return getPackageInfo(packageName, userId, false);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003057 }
3058
Makoto Onuki905e8852016-03-28 10:40:58 -07003059 int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003060 final long token = injectClearCallingIdentity();
Makoto Onuki905e8852016-03-28 10:40:58 -07003061 try {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003062 return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS, userId);
Makoto Onuki905e8852016-03-28 10:40:58 -07003063 } catch (RemoteException e) {
3064 // Shouldn't happen.
3065 Slog.wtf(TAG, "RemoteException", e);
3066 return -1;
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003067 } finally {
3068 injectRestoreCallingIdentity(token);
Makoto Onuki905e8852016-03-28 10:40:58 -07003069 }
Makoto Onuki0acbb142016-03-22 17:02:57 -07003070 }
3071
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003072 /**
3073 * Returns {@link PackageInfo} unless it's uninstalled or disabled.
3074 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003075 @Nullable
Makoto Onuki0acbb142016-03-22 17:02:57 -07003076 @VisibleForTesting
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003077 final PackageInfo getPackageInfo(String packageName, @UserIdInt int userId,
3078 boolean getSignatures) {
3079 return isInstalledOrNull(injectPackageInfoWithUninstalled(
3080 packageName, userId, getSignatures));
3081 }
3082
3083 /**
3084 * Do not use directly; this returns uninstalled packages too.
3085 */
3086 @Nullable
3087 @VisibleForTesting
3088 PackageInfo injectPackageInfoWithUninstalled(String packageName, @UserIdInt int userId,
Makoto Onuki0acbb142016-03-22 17:02:57 -07003089 boolean getSignatures) {
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07003090 final long start = injectElapsedRealtime();
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003091 final long token = injectClearCallingIdentity();
Makoto Onuki0acbb142016-03-22 17:02:57 -07003092 try {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003093 return mIPackageManager.getPackageInfo(
3094 packageName, PACKAGE_MATCH_FLAGS
3095 | (getSignatures ? PackageManager.GET_SIGNATURES : 0), userId);
Makoto Onuki0acbb142016-03-22 17:02:57 -07003096 } catch (RemoteException e) {
3097 // Shouldn't happen.
3098 Slog.wtf(TAG, "RemoteException", e);
3099 return null;
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003100 } finally {
3101 injectRestoreCallingIdentity(token);
Makoto Onuki2e210c42016-03-30 08:30:36 -07003102
3103 logDurationStat(
3104 (getSignatures ? Stats.GET_PACKAGE_INFO_WITH_SIG : Stats.GET_PACKAGE_INFO),
3105 start);
Makoto Onuki0acbb142016-03-22 17:02:57 -07003106 }
3107 }
3108
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003109 /**
3110 * Returns {@link ApplicationInfo} unless it's uninstalled or disabled.
3111 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003112 @Nullable
Makoto Onuki905e8852016-03-28 10:40:58 -07003113 @VisibleForTesting
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003114 final ApplicationInfo getApplicationInfo(String packageName, @UserIdInt int userId) {
3115 return isInstalledOrNull(injectApplicationInfoWithUninstalled(packageName, userId));
3116 }
3117
3118 /**
3119 * Do not use directly; this returns uninstalled packages too.
3120 */
3121 @Nullable
3122 @VisibleForTesting
3123 ApplicationInfo injectApplicationInfoWithUninstalled(
3124 String packageName, @UserIdInt int userId) {
Makoto Onuki6c1dbd52016-05-02 15:19:32 -07003125 final long start = injectElapsedRealtime();
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003126 final long token = injectClearCallingIdentity();
Makoto Onuki905e8852016-03-28 10:40:58 -07003127 try {
3128 return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
3129 } catch (RemoteException e) {
3130 // Shouldn't happen.
3131 Slog.wtf(TAG, "RemoteException", e);
3132 return null;
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003133 } finally {
3134 injectRestoreCallingIdentity(token);
Makoto Onuki2e210c42016-03-30 08:30:36 -07003135
3136 logDurationStat(Stats.GET_APPLICATION_INFO, start);
Makoto Onuki905e8852016-03-28 10:40:58 -07003137 }
3138 }
3139
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003140 /**
3141 * Returns {@link ActivityInfo} with its metadata unless it's uninstalled or disabled.
3142 */
Makoto Onuki22fcc682016-05-17 14:52:19 -07003143 @Nullable
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003144 final ActivityInfo getActivityInfoWithMetadata(ComponentName activity, @UserIdInt int userId) {
3145 return isInstalledOrNull(injectGetActivityInfoWithMetadataWithUninstalled(
3146 activity, userId));
3147 }
3148
3149 /**
3150 * Do not use directly; this returns uninstalled packages too.
3151 */
3152 @Nullable
3153 @VisibleForTesting
3154 ActivityInfo injectGetActivityInfoWithMetadataWithUninstalled(
3155 ComponentName activity, @UserIdInt int userId) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07003156 final long start = injectElapsedRealtime();
3157 final long token = injectClearCallingIdentity();
3158 try {
Makoto Onukib08790c2016-06-23 14:05:46 -07003159 return mIPackageManager.getActivityInfo(activity,
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003160 (PACKAGE_MATCH_FLAGS | PackageManager.GET_META_DATA), userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003161 } catch (RemoteException e) {
3162 // Shouldn't happen.
3163 Slog.wtf(TAG, "RemoteException", e);
3164 return null;
3165 } finally {
3166 injectRestoreCallingIdentity(token);
3167
Makoto Onukib08790c2016-06-23 14:05:46 -07003168 logDurationStat(Stats.GET_ACTIVITY_WITH_METADATA, start);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003169 }
3170 }
3171
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003172 /**
3173 * Return all installed and enabled packages.
3174 */
3175 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07003176 @VisibleForTesting
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003177 final List<PackageInfo> getInstalledPackages(@UserIdInt int userId) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07003178 final long start = injectElapsedRealtime();
3179 final long token = injectClearCallingIdentity();
3180 try {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003181 final List<PackageInfo> all = injectGetPackagesWithUninstalled(userId);
3182
3183 all.removeIf(PACKAGE_NOT_INSTALLED);
3184
3185 return all;
Makoto Onuki22fcc682016-05-17 14:52:19 -07003186 } catch (RemoteException e) {
3187 // Shouldn't happen.
3188 Slog.wtf(TAG, "RemoteException", e);
3189 return null;
3190 } finally {
3191 injectRestoreCallingIdentity(token);
3192
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003193 logDurationStat(Stats.GET_INSTALLED_PACKAGES, start);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003194 }
3195 }
3196
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003197 /**
3198 * Do not use directly; this returns uninstalled packages too.
3199 */
3200 @NonNull
3201 @VisibleForTesting
3202 List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId)
3203 throws RemoteException {
3204 final ParceledListSlice<PackageInfo> parceledList =
3205 mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId);
3206 if (parceledList == null) {
3207 return Collections.emptyList();
3208 }
3209 return parceledList.getList();
3210 }
3211
Makoto Onuki33663282016-08-22 16:19:04 -07003212 private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
Makoto Onuki22fcc682016-05-17 14:52:19 -07003213 Consumer<ApplicationInfo> callback) {
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003214 if (DEBUG) {
Makoto Onuki248a0ef2016-11-03 15:59:01 -07003215 Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime
3216 + " afterOta=" + afterOta);
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003217 }
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003218 final List<PackageInfo> list = getInstalledPackages(userId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003219 for (int i = list.size() - 1; i >= 0; i--) {
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003220 final PackageInfo pi = list.get(i);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003221
Makoto Onuki64183d52016-08-08 14:11:34 -07003222 // If the package has been updated since the last scan time, then scan it.
Makoto Onuki248a0ef2016-11-03 15:59:01 -07003223 // Also if it's right after an OTA, always re-scan all apps anyway, since the
3224 // shortcut parser might have changed.
3225 if (afterOta || (pi.lastUpdateTime >= lastScanTime)) {
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003226 if (DEBUG) {
Makoto Onuki248a0ef2016-11-03 15:59:01 -07003227 Slog.d(TAG, "Found updated package " + pi.packageName
3228 + " updateTime=" + pi.lastUpdateTime);
Makoto Onuki6dd9fb72016-06-01 13:55:54 -07003229 }
3230 callback.accept(pi.applicationInfo);
Makoto Onuki22fcc682016-05-17 14:52:19 -07003231 }
3232 }
3233 }
3234
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003235 private boolean isApplicationFlagSet(@NonNull String packageName, int userId, int flags) {
3236 final ApplicationInfo ai = injectApplicationInfoWithUninstalled(packageName, userId);
Makoto Onuki905e8852016-03-28 10:40:58 -07003237 return (ai != null) && ((ai.flags & flags) == flags);
3238 }
3239
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003240 private static boolean isInstalled(@Nullable ApplicationInfo ai) {
Makoto Onuki82fb2eb2017-03-31 16:58:26 -07003241 return (ai != null) && ai.enabled && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003242 }
3243
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08003244 private static boolean isEphemeralApp(@Nullable ApplicationInfo ai) {
Svetoslav Ganov096d3042017-01-30 16:34:13 -08003245 return (ai != null) && ai.isInstantApp();
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08003246 }
3247
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003248 private static boolean isInstalled(@Nullable PackageInfo pi) {
3249 return (pi != null) && isInstalled(pi.applicationInfo);
3250 }
3251
3252 private static boolean isInstalled(@Nullable ActivityInfo ai) {
3253 return (ai != null) && isInstalled(ai.applicationInfo);
3254 }
3255
3256 private static ApplicationInfo isInstalledOrNull(ApplicationInfo ai) {
3257 return isInstalled(ai) ? ai : null;
3258 }
3259
3260 private static PackageInfo isInstalledOrNull(PackageInfo pi) {
3261 return isInstalled(pi) ? pi : null;
3262 }
3263
3264 private static ActivityInfo isInstalledOrNull(ActivityInfo ai) {
3265 return isInstalled(ai) ? ai : null;
3266 }
3267
Makoto Onuki2e210c42016-03-30 08:30:36 -07003268 boolean isPackageInstalled(String packageName, int userId) {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003269 return getApplicationInfo(packageName, userId) != null;
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003270 }
3271
Makoto Onuki66e4a2b2017-01-23 11:37:45 -08003272 boolean isEphemeralApp(String packageName, int userId) {
3273 return isEphemeralApp(getApplicationInfo(packageName, userId));
3274 }
3275
Makoto Onuki22fcc682016-05-17 14:52:19 -07003276 @Nullable
3277 XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07003278 return activityInfo.loadXmlMetaData(mContext.getPackageManager(), key);
Makoto Onuki39686e82016-04-13 18:03:00 -07003279 }
3280
Makoto Onuki157b1622016-06-02 16:13:10 -07003281 @Nullable
3282 Resources injectGetResourcesForApplicationAsUser(String packageName, int userId) {
3283 final long start = injectElapsedRealtime();
3284 final long token = injectClearCallingIdentity();
3285 try {
3286 return mContext.getPackageManager().getResourcesForApplicationAsUser(
3287 packageName, userId);
3288 } catch (NameNotFoundException e) {
3289 Slog.e(TAG, "Resources for package " + packageName + " not found");
3290 return null;
3291 } finally {
3292 injectRestoreCallingIdentity(token);
3293
3294 logDurationStat(Stats.GET_APPLICATION_RESOURCES, start);
3295 }
3296 }
3297
Makoto Onukib08790c2016-06-23 14:05:46 -07003298 private Intent getMainActivityIntent() {
3299 final Intent intent = new Intent(Intent.ACTION_MAIN);
3300 intent.addCategory(LAUNCHER_INTENT_CATEGORY);
3301 return intent;
3302 }
3303
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003304 /**
3305 * Same as queryIntentActivitiesAsUser, except it makes sure the package is installed,
3306 * and only returns exported activities.
3307 */
3308 @NonNull
3309 @VisibleForTesting
3310 List<ResolveInfo> queryActivities(@NonNull Intent baseIntent,
3311 @NonNull String packageName, @Nullable ComponentName activity, int userId) {
3312
3313 baseIntent.setPackage(Preconditions.checkNotNull(packageName));
3314 if (activity != null) {
3315 baseIntent.setComponent(activity);
3316 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08003317 return queryActivities(baseIntent, userId, /* exportedOnly =*/ true);
3318 }
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003319
Makoto Onuki2d895c32016-12-02 15:48:40 -08003320 @NonNull
3321 List<ResolveInfo> queryActivities(@NonNull Intent intent, int userId,
3322 boolean exportedOnly) {
3323 final List<ResolveInfo> resolved;
3324 final long token = injectClearCallingIdentity();
3325 try {
3326 resolved =
3327 mContext.getPackageManager().queryIntentActivitiesAsUser(
3328 intent, PACKAGE_MATCH_FLAGS, userId);
3329 } finally {
3330 injectRestoreCallingIdentity(token);
3331 }
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003332 if (resolved == null || resolved.size() == 0) {
3333 return EMPTY_RESOLVE_INFO;
3334 }
3335 // Make sure the package is installed.
3336 if (!isInstalled(resolved.get(0).activityInfo)) {
3337 return EMPTY_RESOLVE_INFO;
3338 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08003339 if (exportedOnly) {
3340 resolved.removeIf(ACTIVITY_NOT_EXPORTED);
3341 }
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003342 return resolved;
3343 }
3344
3345 /**
3346 * Return the main activity that is enabled and exported. If multiple activities are found,
3347 * return the first one.
3348 */
Makoto Onukib08790c2016-06-23 14:05:46 -07003349 @Nullable
3350 ComponentName injectGetDefaultMainActivity(@NonNull String packageName, int userId) {
3351 final long start = injectElapsedRealtime();
Makoto Onukib08790c2016-06-23 14:05:46 -07003352 try {
Makoto Onukib08790c2016-06-23 14:05:46 -07003353 final List<ResolveInfo> resolved =
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003354 queryActivities(getMainActivityIntent(), packageName, null, userId);
3355 return resolved.size() == 0 ? null : resolved.get(0).activityInfo.getComponentName();
Makoto Onukib08790c2016-06-23 14:05:46 -07003356 } finally {
Makoto Onukib08790c2016-06-23 14:05:46 -07003357 logDurationStat(Stats.GET_LAUNCHER_ACTIVITY, start);
3358 }
3359 }
3360
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003361 /**
3362 * Return whether an activity is enabled, exported and main.
3363 */
Makoto Onukib08790c2016-06-23 14:05:46 -07003364 boolean injectIsMainActivity(@NonNull ComponentName activity, int userId) {
3365 final long start = injectElapsedRealtime();
Makoto Onukib08790c2016-06-23 14:05:46 -07003366 try {
Makoto Onuki34145532017-03-14 17:58:36 -07003367 if (activity == null) {
3368 wtf("null activity detected");
3369 return false;
3370 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08003371 if (DUMMY_MAIN_ACTIVITY.equals(activity.getClassName())) {
3372 return true;
3373 }
3374 final List<ResolveInfo> resolved = queryActivities(
3375 getMainActivityIntent(), activity.getPackageName(), activity, userId);
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003376 return resolved.size() > 0;
Makoto Onukib08790c2016-06-23 14:05:46 -07003377 } finally {
Makoto Onukib08790c2016-06-23 14:05:46 -07003378 logDurationStat(Stats.CHECK_LAUNCHER_ACTIVITY, start);
3379 }
3380 }
3381
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003382 /**
Makoto Onuki2d895c32016-12-02 15:48:40 -08003383 * Create a dummy "main activity" component name which is used to create a dynamic shortcut
3384 * with no main activity temporarily.
3385 */
3386 @NonNull
3387 ComponentName getDummyMainActivity(@NonNull String packageName) {
3388 return new ComponentName(packageName, DUMMY_MAIN_ACTIVITY);
3389 }
3390
Makoto Onuki255461f2017-01-10 11:47:25 -08003391 boolean isDummyMainActivity(@Nullable ComponentName name) {
3392 return name != null && DUMMY_MAIN_ACTIVITY.equals(name.getClassName());
3393 }
3394
Makoto Onuki2d895c32016-12-02 15:48:40 -08003395 /**
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003396 * Return all the enabled, exported and main activities from a package.
3397 */
Makoto Onukib08790c2016-06-23 14:05:46 -07003398 @NonNull
3399 List<ResolveInfo> injectGetMainActivities(@NonNull String packageName, int userId) {
3400 final long start = injectElapsedRealtime();
Makoto Onukib08790c2016-06-23 14:05:46 -07003401 try {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003402 return queryActivities(getMainActivityIntent(), packageName, null, userId);
Makoto Onukib08790c2016-06-23 14:05:46 -07003403 } finally {
Makoto Onukib08790c2016-06-23 14:05:46 -07003404 logDurationStat(Stats.CHECK_LAUNCHER_ACTIVITY, start);
3405 }
3406 }
3407
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003408 /**
3409 * Return whether an activity is enabled and exported.
3410 */
3411 @VisibleForTesting
3412 boolean injectIsActivityEnabledAndExported(
3413 @NonNull ComponentName activity, @UserIdInt int userId) {
3414 final long start = injectElapsedRealtime();
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003415 try {
3416 return queryActivities(new Intent(), activity.getPackageName(), activity, userId)
3417 .size() > 0;
3418 } finally {
Makoto Onukiee6b6e42016-06-29 17:34:02 -07003419 logDurationStat(Stats.IS_ACTIVITY_ENABLED, start);
3420 }
3421 }
3422
Makoto Onuki2d895c32016-12-02 15:48:40 -08003423 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -08003424 * Get the {@link LauncherApps#ACTION_CONFIRM_PIN_SHORTCUT} or
3425 * {@link LauncherApps#ACTION_CONFIRM_PIN_APPWIDGET} activity in a given package depending on
3426 * the requestType.
Makoto Onuki2d895c32016-12-02 15:48:40 -08003427 */
3428 @Nullable
3429 ComponentName injectGetPinConfirmationActivity(@NonNull String launcherPackageName,
Sunny Goyal7f7372a2017-01-24 11:53:54 -08003430 int launcherUserId, int requestType) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08003431 Preconditions.checkNotNull(launcherPackageName);
Sunny Goyal7f7372a2017-01-24 11:53:54 -08003432 String action = requestType == LauncherApps.PinItemRequest.REQUEST_TYPE_SHORTCUT ?
3433 LauncherApps.ACTION_CONFIRM_PIN_SHORTCUT :
3434 LauncherApps.ACTION_CONFIRM_PIN_APPWIDGET;
Makoto Onuki2d895c32016-12-02 15:48:40 -08003435
Sunny Goyal7f7372a2017-01-24 11:53:54 -08003436 final Intent confirmIntent = new Intent(action).setPackage(launcherPackageName);
Makoto Onuki2d895c32016-12-02 15:48:40 -08003437 final List<ResolveInfo> candidates = queryActivities(
3438 confirmIntent, launcherUserId, /* exportedOnly =*/ false);
3439 for (ResolveInfo ri : candidates) {
3440 return ri.activityInfo.getComponentName();
3441 }
3442 return null;
3443 }
3444
Makoto Onukib08790c2016-06-23 14:05:46 -07003445 boolean injectIsSafeModeEnabled() {
3446 final long token = injectClearCallingIdentity();
3447 try {
3448 return IWindowManager.Stub
3449 .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE))
3450 .isSafeModeEnabled();
3451 } catch (RemoteException e) {
3452 return false; // Shouldn't happen though.
3453 } finally {
3454 injectRestoreCallingIdentity(token);
3455 }
3456 }
3457
Makoto Onuki2d895c32016-12-02 15:48:40 -08003458 /**
3459 * If {@code userId} is of a managed profile, return the parent user ID. Otherwise return
3460 * itself.
3461 */
3462 int getParentOrSelfUserId(int userId) {
3463 final long token = injectClearCallingIdentity();
3464 try {
3465 final UserInfo parent = mUserManager.getProfileParent(userId);
3466 return (parent != null) ? parent.id : userId;
3467 } finally {
3468 injectRestoreCallingIdentity(token);
3469 }
3470 }
3471
Sunny Goyal87a563e2017-01-01 19:42:45 -08003472 void injectSendIntentSender(IntentSender intentSender, Intent extras) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08003473 if (intentSender == null) {
3474 return;
3475 }
3476 try {
Sunny Goyal87a563e2017-01-01 19:42:45 -08003477 intentSender.sendIntent(mContext, /* code= */ 0, extras,
Makoto Onuki2d895c32016-12-02 15:48:40 -08003478 /* onFinished=*/ null, /* handler= */ null);
3479 } catch (SendIntentException e) {
3480 Slog.w(TAG, "sendIntent failed().", e);
3481 }
3482 }
3483
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003484 // === Backup & restore ===
3485
Makoto Onuki0acbb142016-03-22 17:02:57 -07003486 boolean shouldBackupApp(String packageName, int userId) {
Makoto Onuki905e8852016-03-28 10:40:58 -07003487 return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP);
Makoto Onuki0acbb142016-03-22 17:02:57 -07003488 }
3489
Makoto Onukia4f89b12017-10-05 10:37:55 -07003490 static boolean shouldBackupApp(PackageInfo pi) {
Makoto Onuki2e210c42016-03-30 08:30:36 -07003491 return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
3492 }
3493
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003494 @Override
Makoto Onuki2e210c42016-03-30 08:30:36 -07003495 public byte[] getBackupPayload(@UserIdInt int userId) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003496 enforceSystem();
3497 if (DEBUG) {
3498 Slog.d(TAG, "Backing up user " + userId);
3499 }
3500 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07003501 if (!isUserUnlockedL(userId)) {
3502 wtf("Can't backup: user " + userId + " is locked or not running");
3503 return null;
3504 }
3505
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003506 final ShortcutUser user = getUserShortcutsLocked(userId);
3507 if (user == null) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07003508 wtf("Can't backup: user not found: id=" + userId);
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003509 return null;
3510 }
3511
Makoto Onukic8c33292016-09-12 16:36:59 -07003512 // Update the signatures for all packages.
3513 user.forAllPackageItems(spi -> spi.refreshPackageSignatureAndSave());
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003514
Makoto Onukic8c33292016-09-12 16:36:59 -07003515 // Set the version code for the launchers.
3516 // We shouldn't do this for publisher packages, because we don't want to update the
3517 // version code without rescanning the manifest.
Makoto Onukia4f89b12017-10-05 10:37:55 -07003518 user.forAllLaunchers(launcher -> launcher.ensurePackageInfo());
Makoto Onukic8c33292016-09-12 16:36:59 -07003519
3520 // Save to the filesystem.
3521 scheduleSaveUser(userId);
3522 saveDirtyInfo();
3523
Makoto Onuki475c3652017-05-08 14:29:03 -07003524 // Note, in case of backup, we don't have to wait on bitmap saving, because we don't
3525 // back up bitmaps anyway.
3526
Makoto Onukic8c33292016-09-12 16:36:59 -07003527 // Then create the backup payload.
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003528 final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
3529 try {
3530 saveUserInternalLocked(userId, os, /* forBackup */ true);
Makoto Onukib08790c2016-06-23 14:05:46 -07003531 } catch (XmlPullParserException | IOException e) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003532 // Shouldn't happen.
3533 Slog.w(TAG, "Backup failed.", e);
3534 return null;
3535 }
3536 return os.toByteArray();
3537 }
3538 }
3539
3540 @Override
Makoto Onuki2e210c42016-03-30 08:30:36 -07003541 public void applyRestore(byte[] payload, @UserIdInt int userId) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003542 enforceSystem();
3543 if (DEBUG) {
3544 Slog.d(TAG, "Restoring user " + userId);
3545 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003546 synchronized (mLock) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07003547 if (!isUserUnlockedL(userId)) {
3548 wtf("Can't restore: user " + userId + " is locked or not running");
3549 return;
3550 }
Makoto Onuki50a320e2017-05-31 14:38:42 -07003551
3552 // Note we print the file timestamps in dumpsys too, but also printing the timestamp
3553 // in the files anyway.
3554 mShortcutDumpFiles.save("restore-0-start.txt", pw -> {
3555 pw.print("Start time: ");
3556 dumpCurrentTime(pw);
3557 pw.println();
3558 });
3559 mShortcutDumpFiles.save("restore-1-payload.xml", payload);
3560
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07003561 // Actually do restore.
3562 final ShortcutUser restored;
Makoto Onuki02f338e2016-07-29 09:40:40 -07003563 final ByteArrayInputStream is = new ByteArrayInputStream(payload);
3564 try {
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07003565 restored = loadUserInternal(userId, is, /* fromBackup */ true);
3566 } catch (XmlPullParserException | IOException | InvalidFileFormatException e) {
Makoto Onuki02f338e2016-07-29 09:40:40 -07003567 Slog.w(TAG, "Restoration failed.", e);
3568 return;
3569 }
Makoto Onuki50a320e2017-05-31 14:38:42 -07003570 mShortcutDumpFiles.save("restore-2.txt", this::dumpInner);
3571
Makoto Onukifc4cf2d2016-08-24 11:10:26 -07003572 getUserShortcutsLocked(userId).mergeRestoredFile(restored);
Makoto Onuki2e210c42016-03-30 08:30:36 -07003573
Makoto Onuki50a320e2017-05-31 14:38:42 -07003574 mShortcutDumpFiles.save("restore-3.txt", this::dumpInner);
3575
Makoto Onuki377b7972016-08-09 14:43:55 -07003576 // Rescan all packages to re-publish manifest shortcuts and do other checks.
3577 rescanUpdatedPackagesLocked(userId,
Makoto Onuki248a0ef2016-11-03 15:59:01 -07003578 0 // lastScanTime = 0; rescan all packages.
3579 );
Makoto Onuki2e210c42016-03-30 08:30:36 -07003580
Makoto Onuki50a320e2017-05-31 14:38:42 -07003581 mShortcutDumpFiles.save("restore-4.txt", this::dumpInner);
3582
3583 mShortcutDumpFiles.save("restore-5-finish.txt", pw -> {
3584 pw.print("Finish time: ");
3585 dumpCurrentTime(pw);
3586 pw.println();
3587 });
3588
Makoto Onuki2e210c42016-03-30 08:30:36 -07003589 saveUserLocked(userId);
Makoto Onuki9da23fc2016-03-29 11:14:42 -07003590 }
Makoto Onukicdc78f72016-03-21 15:47:52 -07003591 }
3592
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003593 // === Dump ===
3594
3595 @Override
3596 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003597 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
Makoto Onukic4361e32017-04-03 11:24:25 -07003598 dumpNoCheck(fd, pw, args);
3599 }
3600
3601 @VisibleForTesting
3602 void dumpNoCheck(FileDescriptor fd, PrintWriter pw, String[] args) {
Makoto Onuki20b82212017-10-04 15:03:50 -07003603 final DumpFilter filter = parseDumpArgs(args);
Makoto Onuki50a320e2017-05-31 14:38:42 -07003604
Makoto Onuki20b82212017-10-04 15:03:50 -07003605 if (filter.shouldDumpCheckIn()) {
Makoto Onuki50a320e2017-05-31 14:38:42 -07003606 // Other flags are not supported for checkin.
Makoto Onuki20b82212017-10-04 15:03:50 -07003607 dumpCheckin(pw, filter.shouldCheckInClear());
Makoto Onuki76269922016-07-15 14:58:54 -07003608 } else {
Makoto Onuki20b82212017-10-04 15:03:50 -07003609 if (filter.shouldDumpMain()) {
3610 dumpInner(pw, filter);
Makoto Onuki50a320e2017-05-31 14:38:42 -07003611 pw.println();
3612 }
Makoto Onuki20b82212017-10-04 15:03:50 -07003613 if (filter.shouldDumpUid()) {
Makoto Onuki50a320e2017-05-31 14:38:42 -07003614 dumpUid(pw);
3615 pw.println();
3616 }
Makoto Onuki20b82212017-10-04 15:03:50 -07003617 if (filter.shouldDumpFiles()) {
Makoto Onuki50a320e2017-05-31 14:38:42 -07003618 dumpDumpFiles(pw);
3619 pw.println();
3620 }
Makoto Onuki76269922016-07-15 14:58:54 -07003621 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003622 }
3623
Makoto Onuki20b82212017-10-04 15:03:50 -07003624 private static DumpFilter parseDumpArgs(String[] args) {
3625 final DumpFilter filter = new DumpFilter();
3626 if (args == null) {
3627 return filter;
3628 }
Makoto Onuki55046222016-03-08 10:49:47 -08003629
Makoto Onuki20b82212017-10-04 15:03:50 -07003630 int argIndex = 0;
3631 while (argIndex < args.length) {
3632 final String arg = args[argIndex++];
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003633
Makoto Onuki20b82212017-10-04 15:03:50 -07003634 if ("-c".equals(arg)) {
3635 filter.setDumpCheckIn(true);
3636 continue;
3637 }
3638 if ("--checkin".equals(arg)) {
3639 filter.setDumpCheckIn(true);
3640 filter.setCheckInClear(true);
3641 continue;
3642 }
3643 if ("-a".equals(arg) || "--all".equals(arg)) {
3644 filter.setDumpUid(true);
3645 filter.setDumpFiles(true);
3646 continue;
3647 }
3648 if ("-u".equals(arg) || "--uid".equals(arg)) {
3649 filter.setDumpUid(true);
3650 continue;
3651 }
3652 if ("-f".equals(arg) || "--files".equals(arg)) {
3653 filter.setDumpFiles(true);
3654 continue;
3655 }
3656 if ("-n".equals(arg) || "--no-main".equals(arg)) {
3657 filter.setDumpMain(false);
3658 continue;
3659 }
3660 if ("--user".equals(arg)) {
3661 if (argIndex >= args.length) {
3662 throw new IllegalArgumentException("Missing user ID for --user");
3663 }
3664 try {
3665 filter.addUser(Integer.parseInt(args[argIndex++]));
3666 } catch (NumberFormatException e) {
3667 throw new IllegalArgumentException("Invalid user ID", e);
3668 }
3669 continue;
3670 }
3671 if ("-p".equals(arg) || "--package".equals(arg)) {
3672 if (argIndex >= args.length) {
3673 throw new IllegalArgumentException("Missing package name for --package");
3674 }
3675 filter.addPackageRegex(args[argIndex++]);
3676 filter.setDumpDetails(false);
3677 continue;
3678 }
3679 if (arg.startsWith("-")) {
3680 throw new IllegalArgumentException("Unknown option " + arg);
3681 }
3682 break;
3683 }
3684 while (argIndex < args.length) {
3685 filter.addPackage(args[argIndex++]);
3686 }
3687 return filter;
3688 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003689
Makoto Onuki20b82212017-10-04 15:03:50 -07003690 static class DumpFilter {
3691 private boolean mDumpCheckIn = false;
3692 private boolean mCheckInClear = false;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07003693
Makoto Onuki20b82212017-10-04 15:03:50 -07003694 private boolean mDumpMain = true;
3695 private boolean mDumpUid = false;
3696 private boolean mDumpFiles = false;
Makoto Onuki55046222016-03-08 10:49:47 -08003697
Makoto Onuki20b82212017-10-04 15:03:50 -07003698 private boolean mDumpDetails = true;
3699 private List<Pattern> mPackagePatterns = new ArrayList<>();
3700 private List<Integer> mUsers = new ArrayList<>();
3701
3702 void addPackageRegex(String regex) {
3703 mPackagePatterns.add(Pattern.compile(regex));
3704 }
3705
3706 public void addPackage(String packageName) {
3707 addPackageRegex(Pattern.quote(packageName));
3708 }
3709
3710 void addUser(int userId) {
3711 mUsers.add(userId);
3712 }
3713
3714 boolean isPackageMatch(String packageName) {
3715 if (mPackagePatterns.size() == 0) {
3716 return true;
3717 }
3718 for (int i = 0; i < mPackagePatterns.size(); i++) {
3719 if (mPackagePatterns.get(i).matcher(packageName).find()) {
3720 return true;
Makoto Onuki085a05c2016-08-19 11:39:29 -07003721 }
Makoto Onuki2e210c42016-03-30 08:30:36 -07003722 }
Makoto Onuki20b82212017-10-04 15:03:50 -07003723 return false;
3724 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003725
Makoto Onuki20b82212017-10-04 15:03:50 -07003726 boolean isUserMatch(int userId) {
3727 if (mUsers.size() == 0) {
3728 return true;
3729 }
3730 for (int i = 0; i < mUsers.size(); i++) {
3731 if (mUsers.get(i) == userId) {
3732 return true;
3733 }
3734 }
3735 return false;
3736 }
Makoto Onukia2241832016-07-06 13:28:37 -07003737
Makoto Onuki20b82212017-10-04 15:03:50 -07003738 public boolean shouldDumpCheckIn() {
3739 return mDumpCheckIn;
3740 }
3741
3742 public void setDumpCheckIn(boolean dumpCheckIn) {
3743 mDumpCheckIn = dumpCheckIn;
3744 }
3745
3746 public boolean shouldCheckInClear() {
3747 return mCheckInClear;
3748 }
3749
3750 public void setCheckInClear(boolean checkInClear) {
3751 mCheckInClear = checkInClear;
3752 }
3753
3754 public boolean shouldDumpMain() {
3755 return mDumpMain;
3756 }
3757
3758 public void setDumpMain(boolean dumpMain) {
3759 mDumpMain = dumpMain;
3760 }
3761
3762 public boolean shouldDumpUid() {
3763 return mDumpUid;
3764 }
3765
3766 public void setDumpUid(boolean dumpUid) {
3767 mDumpUid = dumpUid;
3768 }
3769
3770 public boolean shouldDumpFiles() {
3771 return mDumpFiles;
3772 }
3773
3774 public void setDumpFiles(boolean dumpFiles) {
3775 mDumpFiles = dumpFiles;
3776 }
3777
3778 public boolean shouldDumpDetails() {
3779 return mDumpDetails;
3780 }
3781
3782 public void setDumpDetails(boolean dumpDetails) {
3783 mDumpDetails = dumpDetails;
3784 }
3785 }
3786
3787 private void dumpInner(PrintWriter pw) {
3788 dumpInner(pw, new DumpFilter());
3789 }
3790
3791 private void dumpInner(PrintWriter pw, DumpFilter filter) {
3792 synchronized (mLock) {
3793 if (filter.shouldDumpDetails()) {
3794 final long now = injectCurrentTimeMillis();
3795 pw.print("Now: [");
3796 pw.print(now);
3797 pw.print("] ");
3798 pw.print(formatTime(now));
3799
3800 pw.print(" Raw last reset: [");
3801 pw.print(mRawLastResetTime);
3802 pw.print("] ");
3803 pw.print(formatTime(mRawLastResetTime));
3804
3805 final long last = getLastResetTimeLocked();
3806 pw.print(" Last reset: [");
3807 pw.print(last);
3808 pw.print("] ");
3809 pw.print(formatTime(last));
3810
3811 final long next = getNextResetTimeLocked();
3812 pw.print(" Next reset: [");
3813 pw.print(next);
3814 pw.print("] ");
3815 pw.print(formatTime(next));
3816
3817 pw.print(" Config:");
3818 pw.print(" Max icon dim: ");
3819 pw.println(mMaxIconDimension);
3820 pw.print(" Icon format: ");
3821 pw.println(mIconPersistFormat);
3822 pw.print(" Icon quality: ");
3823 pw.println(mIconPersistQuality);
3824 pw.print(" saveDelayMillis: ");
3825 pw.println(mSaveDelayMillis);
3826 pw.print(" resetInterval: ");
3827 pw.println(mResetInterval);
3828 pw.print(" maxUpdatesPerInterval: ");
3829 pw.println(mMaxUpdatesPerInterval);
3830 pw.print(" maxShortcutsPerActivity: ");
3831 pw.println(mMaxShortcuts);
3832 pw.println();
3833
3834 pw.println(" Stats:");
3835 synchronized (mStatLock) {
3836 for (int i = 0; i < Stats.COUNT; i++) {
3837 dumpStatLS(pw, " ", i);
3838 }
3839 }
3840
3841 pw.println();
3842 pw.print(" #Failures: ");
3843 pw.println(mWtfCount);
3844
3845 if (mLastWtfStacktrace != null) {
3846 pw.print(" Last failure stack trace: ");
3847 pw.println(Log.getStackTraceString(mLastWtfStacktrace));
3848 }
3849
3850 pw.println();
3851 mShortcutBitmapSaver.dumpLocked(pw, " ");
3852
3853 pw.println();
Makoto Onukia2241832016-07-06 13:28:37 -07003854 }
3855
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -08003856 for (int i = 0; i < mUsers.size(); i++) {
Makoto Onuki20b82212017-10-04 15:03:50 -07003857 final ShortcutUser user = mUsers.valueAt(i);
3858 if (filter.isUserMatch(user.getUserId())) {
3859 user.dump(pw, " ", filter);
3860 pw.println();
3861 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003862 }
Makoto Onuki708703b2017-12-11 16:38:11 -08003863
3864 for (int i = 0; i < mShortcutNonPersistentUsers.size(); i++) {
3865 final ShortcutNonPersistentUser user = mShortcutNonPersistentUsers.valueAt(i);
3866 if (filter.isUserMatch(user.getUserId())) {
3867 user.dump(pw, " ", filter);
3868 pw.println();
3869 }
3870 }
Makoto Onuki50a320e2017-05-31 14:38:42 -07003871 }
3872 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07003873
Makoto Onuki50a320e2017-05-31 14:38:42 -07003874 private void dumpUid(PrintWriter pw) {
3875 synchronized (mLock) {
3876 pw.println("** SHORTCUT MANAGER UID STATES (dumpsys shortcut -n -u)");
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07003877
3878 for (int i = 0; i < mUidState.size(); i++) {
3879 final int uid = mUidState.keyAt(i);
3880 final int state = mUidState.valueAt(i);
3881 pw.print(" UID=");
3882 pw.print(uid);
3883 pw.print(" state=");
3884 pw.print(state);
3885 if (isProcessStateForeground(state)) {
3886 pw.print(" [FG]");
3887 }
3888 pw.print(" last FG=");
3889 pw.print(mUidLastForegroundElapsedTime.get(uid));
3890 pw.println();
3891 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003892 }
3893 }
3894
Makoto Onuki41066a62016-03-09 16:18:44 -08003895 static String formatTime(long time) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003896 Time tobj = new Time();
3897 tobj.set(time);
3898 return tobj.format("%Y-%m-%d %H:%M:%S");
3899 }
3900
Makoto Onuki50a320e2017-05-31 14:38:42 -07003901 private void dumpCurrentTime(PrintWriter pw) {
3902 pw.print(formatTime(injectCurrentTimeMillis()));
3903 }
3904
Makoto Onuki085a05c2016-08-19 11:39:29 -07003905 private void dumpStatLS(PrintWriter pw, String prefix, int statId) {
Makoto Onuki2e210c42016-03-30 08:30:36 -07003906 pw.print(prefix);
3907 final int count = mCountStats[statId];
3908 final long dur = mDurationStats[statId];
3909 pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
Makoto Onuki085a05c2016-08-19 11:39:29 -07003910 STAT_LABELS[statId], count, dur,
Makoto Onuki2e210c42016-03-30 08:30:36 -07003911 (count == 0 ? 0 : ((double) dur) / count)));
3912 }
3913
Makoto Onuki76269922016-07-15 14:58:54 -07003914 /**
3915 * Dumpsys for checkin.
3916 *
3917 * @param clear if true, clear the history information. Some other system services have this
3918 * behavior but shortcut service doesn't for now.
3919 */
3920 private void dumpCheckin(PrintWriter pw, boolean clear) {
3921 synchronized (mLock) {
3922 try {
3923 final JSONArray users = new JSONArray();
3924
3925 for (int i = 0; i < mUsers.size(); i++) {
3926 users.put(mUsers.valueAt(i).dumpCheckin(clear));
3927 }
3928
3929 final JSONObject result = new JSONObject();
3930
3931 result.put(KEY_SHORTCUT, users);
3932 result.put(KEY_LOW_RAM, injectIsLowRamDevice());
3933 result.put(KEY_ICON_SIZE, mMaxIconDimension);
3934
3935 pw.println(result.toString(1));
3936 } catch (JSONException e) {
3937 Slog.e(TAG, "Unable to write in json", e);
3938 }
3939 }
3940 }
3941
Makoto Onuki50a320e2017-05-31 14:38:42 -07003942 private void dumpDumpFiles(PrintWriter pw) {
3943 synchronized (mLock) {
3944 pw.println("** SHORTCUT MANAGER FILES (dumpsys shortcut -n -f)");
3945 mShortcutDumpFiles.dumpAll(pw);
3946 }
3947 }
3948
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003949 // === Shell support ===
3950
3951 @Override
3952 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
Dianne Hackborn354736e2016-08-22 17:00:05 -07003953 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003954
3955 enforceShell();
3956
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07003957 final long token = injectClearCallingIdentity();
3958 try {
Dianne Hackborn354736e2016-08-22 17:00:05 -07003959 final int status = (new MyShellCommand()).exec(this, in, out, err, args, callback,
3960 resultReceiver);
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07003961 resultReceiver.send(status, null);
3962 } finally {
3963 injectRestoreCallingIdentity(token);
3964 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003965 }
3966
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003967 static class CommandException extends Exception {
3968 public CommandException(String message) {
3969 super(message);
3970 }
3971 }
3972
Makoto Onuki6f7362d92016-03-04 13:39:41 -08003973 /**
3974 * Handle "adb shell cmd".
3975 */
3976 private class MyShellCommand extends ShellCommand {
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003977
3978 private int mUserId = UserHandle.USER_SYSTEM;
3979
Makoto Onuki02f338e2016-07-29 09:40:40 -07003980 private void parseOptionsLocked(boolean takeUser)
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003981 throws CommandException {
3982 String opt;
3983 while ((opt = getNextOption()) != null) {
3984 switch (opt) {
3985 case "--user":
3986 if (takeUser) {
3987 mUserId = UserHandle.parseUserArg(getNextArgRequired());
Makoto Onuki02f338e2016-07-29 09:40:40 -07003988 if (!isUserUnlockedL(mUserId)) {
Makoto Onukif34c3082016-07-13 10:25:25 -07003989 throw new CommandException(
3990 "User " + mUserId + " is not running or locked");
3991 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08003992 break;
3993 }
3994 // fallthrough
3995 default:
3996 throw new CommandException("Unknown option: " + opt);
3997 }
3998 }
3999 }
4000
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004001 @Override
4002 public int onCommand(String cmd) {
4003 if (cmd == null) {
4004 return handleDefaultCommands(cmd);
4005 }
4006 final PrintWriter pw = getOutPrintWriter();
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004007 try {
4008 switch (cmd) {
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004009 case "reset-throttling":
4010 handleResetThrottling();
4011 break;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004012 case "reset-all-throttling":
4013 handleResetAllThrottling();
4014 break;
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004015 case "override-config":
4016 handleOverrideConfig();
4017 break;
4018 case "reset-config":
4019 handleResetConfig();
4020 break;
4021 case "clear-default-launcher":
4022 handleClearDefaultLauncher();
4023 break;
4024 case "get-default-launcher":
4025 handleGetDefaultLauncher();
4026 break;
Makoto Onukiac214972016-04-04 10:19:45 -07004027 case "unload-user":
4028 handleUnloadUser();
4029 break;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004030 case "clear-shortcuts":
4031 handleClearShortcuts();
4032 break;
Makoto Onukib08790c2016-06-23 14:05:46 -07004033 case "verify-states": // hidden command to verify various internal states.
4034 handleVerifyStates();
4035 break;
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004036 default:
4037 return handleDefaultCommands(cmd);
4038 }
4039 } catch (CommandException e) {
4040 pw.println("Error: " + e.getMessage());
4041 return 1;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004042 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004043 pw.println("Success");
4044 return 0;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004045 }
4046
4047 @Override
4048 public void onHelp() {
4049 final PrintWriter pw = getOutPrintWriter();
4050 pw.println("Usage: cmd shortcut COMMAND [options ...]");
4051 pw.println();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004052 pw.println("cmd shortcut reset-throttling [--user USER_ID]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004053 pw.println(" Reset throttling for all packages and users");
4054 pw.println();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004055 pw.println("cmd shortcut reset-all-throttling");
4056 pw.println(" Reset the throttling state for all users");
4057 pw.println();
Makoto Onuki4362a662016-03-08 18:59:09 -08004058 pw.println("cmd shortcut override-config CONFIG");
4059 pw.println(" Override the configuration for testing (will last until reboot)");
4060 pw.println();
4061 pw.println("cmd shortcut reset-config");
4062 pw.println(" Reset the configuration set with \"update-config\"");
4063 pw.println();
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004064 pw.println("cmd shortcut clear-default-launcher [--user USER_ID]");
4065 pw.println(" Clear the cached default launcher");
4066 pw.println();
4067 pw.println("cmd shortcut get-default-launcher [--user USER_ID]");
Makoto Onuki0b9d1db2016-07-18 14:16:41 -07004068 pw.println(" Show the default launcher");
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004069 pw.println();
Makoto Onukiac214972016-04-04 10:19:45 -07004070 pw.println("cmd shortcut unload-user [--user USER_ID]");
4071 pw.println(" Unload a user from the memory");
4072 pw.println(" (This should not affect any observable behavior)");
4073 pw.println();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004074 pw.println("cmd shortcut clear-shortcuts [--user USER_ID] PACKAGE");
4075 pw.println(" Remove all shortcuts from a package, including pinned shortcuts");
4076 pw.println();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004077 }
4078
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004079 private void handleResetThrottling() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004080 synchronized (mLock) {
4081 parseOptionsLocked(/* takeUser =*/ true);
Makoto Onuki4554d0e2016-03-14 15:51:41 -07004082
Makoto Onuki02f338e2016-07-29 09:40:40 -07004083 Slog.i(TAG, "cmd: handleResetThrottling: user=" + mUserId);
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004084
Makoto Onuki02f338e2016-07-29 09:40:40 -07004085 resetThrottlingInner(mUserId);
4086 }
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004087 }
4088
4089 private void handleResetAllThrottling() {
4090 Slog.i(TAG, "cmd: handleResetAllThrottling");
4091
4092 resetAllThrottlingInner();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004093 }
4094
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004095 private void handleOverrideConfig() throws CommandException {
Makoto Onuki4362a662016-03-08 18:59:09 -08004096 final String config = getNextArgRequired();
4097
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004098 Slog.i(TAG, "cmd: handleOverrideConfig: " + config);
4099
Makoto Onuki4362a662016-03-08 18:59:09 -08004100 synchronized (mLock) {
4101 if (!updateConfigurationLocked(config)) {
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004102 throw new CommandException("override-config failed. See logcat for details.");
Makoto Onuki4362a662016-03-08 18:59:09 -08004103 }
4104 }
Makoto Onuki4362a662016-03-08 18:59:09 -08004105 }
4106
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004107 private void handleResetConfig() {
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004108 Slog.i(TAG, "cmd: handleResetConfig");
4109
Makoto Onuki4362a662016-03-08 18:59:09 -08004110 synchronized (mLock) {
4111 loadConfigurationLocked();
4112 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004113 }
4114
4115 private void clearLauncher() {
4116 synchronized (mLock) {
Makoto Onuki10305202016-07-14 18:14:08 -07004117 getUserShortcutsLocked(mUserId).forceClearLauncher();
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004118 }
4119 }
4120
4121 private void showLauncher() {
4122 synchronized (mLock) {
4123 // This ensures to set the cached launcher. Package name doesn't matter.
4124 hasShortcutHostPermissionInner("-", mUserId);
4125
4126 getOutPrintWriter().println("Launcher: "
Makoto Onuki10305202016-07-14 18:14:08 -07004127 + getUserShortcutsLocked(mUserId).getLastKnownLauncher());
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004128 }
4129 }
4130
4131 private void handleClearDefaultLauncher() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004132 synchronized (mLock) {
4133 parseOptionsLocked(/* takeUser =*/ true);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004134
Makoto Onuki02f338e2016-07-29 09:40:40 -07004135 clearLauncher();
4136 }
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004137 }
4138
4139 private void handleGetDefaultLauncher() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004140 synchronized (mLock) {
4141 parseOptionsLocked(/* takeUser =*/ true);
Makoto Onuki2d5b4652016-03-11 16:09:54 -08004142
Makoto Onuki02f338e2016-07-29 09:40:40 -07004143 clearLauncher();
4144 showLauncher();
4145 }
Makoto Onuki4362a662016-03-08 18:59:09 -08004146 }
Makoto Onukiac214972016-04-04 10:19:45 -07004147
4148 private void handleUnloadUser() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004149 synchronized (mLock) {
4150 parseOptionsLocked(/* takeUser =*/ true);
Makoto Onukiac214972016-04-04 10:19:45 -07004151
Makoto Onuki02f338e2016-07-29 09:40:40 -07004152 Slog.i(TAG, "cmd: handleUnloadUser: user=" + mUserId);
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004153
Makoto Onuki01ce92b2017-04-28 12:24:16 -07004154 ShortcutService.this.handleStopUser(mUserId);
Makoto Onuki02f338e2016-07-29 09:40:40 -07004155 }
Makoto Onukiac214972016-04-04 10:19:45 -07004156 }
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004157
4158 private void handleClearShortcuts() throws CommandException {
Makoto Onuki02f338e2016-07-29 09:40:40 -07004159 synchronized (mLock) {
4160 parseOptionsLocked(/* takeUser =*/ true);
4161 final String packageName = getNextArgRequired();
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004162
Makoto Onuki02f338e2016-07-29 09:40:40 -07004163 Slog.i(TAG, "cmd: handleClearShortcuts: user" + mUserId + ", " + packageName);
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004164
Makoto Onuki02f338e2016-07-29 09:40:40 -07004165 ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId,
4166 /* appStillExists = */ true);
4167 }
Makoto Onukib08790c2016-06-23 14:05:46 -07004168 }
4169
4170 private void handleVerifyStates() throws CommandException {
4171 try {
4172 verifyStatesForce(); // This will throw when there's an issue.
4173 } catch (Throwable th) {
4174 throw new CommandException(th.getMessage() + "\n" + Log.getStackTraceString(th));
4175 }
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -07004176 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004177 }
4178
4179 // === Unit test support ===
4180
4181 // Injection point.
Makoto Onuki31459242016-03-22 11:12:18 -07004182 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004183 long injectCurrentTimeMillis() {
4184 return System.currentTimeMillis();
4185 }
4186
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07004187 @VisibleForTesting
4188 long injectElapsedRealtime() {
4189 return SystemClock.elapsedRealtime();
4190 }
4191
Makoto Onuki475c3652017-05-08 14:29:03 -07004192 @VisibleForTesting
4193 long injectUptimeMillis() {
4194 return SystemClock.uptimeMillis();
4195 }
4196
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004197 // Injection point.
Makoto Onuki31459242016-03-22 11:12:18 -07004198 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004199 int injectBinderCallingUid() {
4200 return getCallingUid();
4201 }
4202
Makoto Onuki31459242016-03-22 11:12:18 -07004203 private int getCallingUserId() {
Makoto Onuki4554d0e2016-03-14 15:51:41 -07004204 return UserHandle.getUserId(injectBinderCallingUid());
4205 }
4206
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07004207 // Injection point.
Makoto Onuki31459242016-03-22 11:12:18 -07004208 @VisibleForTesting
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07004209 long injectClearCallingIdentity() {
4210 return Binder.clearCallingIdentity();
4211 }
4212
4213 // Injection point.
Makoto Onuki31459242016-03-22 11:12:18 -07004214 @VisibleForTesting
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07004215 void injectRestoreCallingIdentity(long token) {
4216 Binder.restoreCallingIdentity(token);
4217 }
4218
Makoto Onuki33663282016-08-22 16:19:04 -07004219 // Injection point.
4220 @VisibleForTesting
4221 String injectBuildFingerprint() {
4222 return Build.FINGERPRINT;
4223 }
4224
Makoto Onukide667372016-03-15 14:29:20 -07004225 final void wtf(String message) {
Makoto Onukib08790c2016-06-23 14:05:46 -07004226 wtf(message, /* exception= */ null);
Makoto Onukide667372016-03-15 14:29:20 -07004227 }
4228
Makoto Onuki2e210c42016-03-30 08:30:36 -07004229 // Injection point.
Makoto Onukia2241832016-07-06 13:28:37 -07004230 void wtf(String message, Throwable e) {
4231 if (e == null) {
4232 e = new RuntimeException("Stacktrace");
4233 }
4234 synchronized (mLock) {
4235 mWtfCount++;
4236 mLastWtfStacktrace = new Exception("Last failure was logged here:");
4237 }
Makoto Onukide667372016-03-15 14:29:20 -07004238 Slog.wtf(TAG, message, e);
4239 }
4240
Makoto Onuki31459242016-03-22 11:12:18 -07004241 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004242 File injectSystemDataPath() {
4243 return Environment.getDataSystemDirectory();
4244 }
4245
Makoto Onuki31459242016-03-22 11:12:18 -07004246 @VisibleForTesting
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004247 File injectUserDataPath(@UserIdInt int userId) {
Makoto Onuki55046222016-03-08 10:49:47 -08004248 return new File(Environment.getDataSystemCeDirectory(userId), DIRECTORY_PER_USER);
4249 }
4250
Makoto Onuki50a320e2017-05-31 14:38:42 -07004251 public File getDumpPath() {
4252 return new File(injectUserDataPath(UserHandle.USER_SYSTEM), DIRECTORY_DUMP);
4253 }
4254
Makoto Onuki4362a662016-03-08 18:59:09 -08004255 @VisibleForTesting
Makoto Onuki55046222016-03-08 10:49:47 -08004256 boolean injectIsLowRamDevice() {
4257 return ActivityManager.isLowRamDeviceStatic();
4258 }
4259
Makoto Onuki31459242016-03-22 11:12:18 -07004260 @VisibleForTesting
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07004261 void injectRegisterUidObserver(IUidObserver observer, int which) {
4262 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08004263 ActivityManager.getService().registerUidObserver(observer, which,
Dianne Hackborn5614bf52016-11-07 17:26:41 -08004264 ActivityManager.PROCESS_STATE_UNKNOWN, null);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07004265 } catch (RemoteException shouldntHappen) {
4266 }
4267 }
4268
Makoto Onuki55046222016-03-08 10:49:47 -08004269 File getUserBitmapFilePath(@UserIdInt int userId) {
4270 return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004271 }
4272
4273 @VisibleForTesting
Makoto Onuki31459242016-03-22 11:12:18 -07004274 SparseArray<ShortcutUser> getShortcutsForTest() {
Makoto Onuki3f4b1ca2016-03-11 13:44:32 -08004275 return mUsers;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004276 }
4277
4278 @VisibleForTesting
Makoto Onukib5a012f2016-06-21 11:13:53 -07004279 int getMaxShortcutsForTest() {
4280 return mMaxShortcuts;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004281 }
4282
4283 @VisibleForTesting
Makoto Onukib6d35232016-04-04 15:57:17 -07004284 int getMaxUpdatesPerIntervalForTest() {
4285 return mMaxUpdatesPerInterval;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004286 }
4287
4288 @VisibleForTesting
Makoto Onuki4362a662016-03-08 18:59:09 -08004289 long getResetIntervalForTest() {
4290 return mResetInterval;
Makoto Onuki55046222016-03-08 10:49:47 -08004291 }
4292
4293 @VisibleForTesting
Makoto Onuki4362a662016-03-08 18:59:09 -08004294 int getMaxIconDimensionForTest() {
4295 return mMaxIconDimension;
4296 }
4297
4298 @VisibleForTesting
4299 CompressFormat getIconPersistFormatForTest() {
4300 return mIconPersistFormat;
4301 }
4302
4303 @VisibleForTesting
4304 int getIconPersistQualityForTest() {
4305 return mIconPersistQuality;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08004306 }
Makoto Onuki41066a62016-03-09 16:18:44 -08004307
4308 @VisibleForTesting
Makoto Onuki22fcc682016-05-17 14:52:19 -07004309 ShortcutPackage getPackageShortcutForTest(String packageName, int userId) {
Makoto Onuki41066a62016-03-09 16:18:44 -08004310 synchronized (mLock) {
Makoto Onuki31459242016-03-22 11:12:18 -07004311 final ShortcutUser user = mUsers.get(userId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07004312 if (user == null) return null;
4313
Makoto Onuki22fcc682016-05-17 14:52:19 -07004314 return user.getAllPackagesForTest().get(packageName);
4315 }
4316 }
4317
4318 @VisibleForTesting
4319 ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) {
4320 synchronized (mLock) {
Makoto Onukif34c3082016-07-13 10:25:25 -07004321 final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId);
Makoto Onukicdc78f72016-03-21 15:47:52 -07004322 if (pkg == null) return null;
4323
4324 return pkg.findShortcutById(shortcutId);
Makoto Onuki41066a62016-03-09 16:18:44 -08004325 }
4326 }
Makoto Onuki7001a612016-05-27 13:24:28 -07004327
Makoto Onukifac592f2016-11-21 13:41:32 -08004328 @VisibleForTesting
4329 ShortcutLauncher getLauncherShortcutForTest(String packageName, int userId) {
4330 synchronized (mLock) {
4331 final ShortcutUser user = mUsers.get(userId);
4332 if (user == null) return null;
4333
4334 return user.getAllLaunchersForTest().get(PackageWithUser.of(userId, packageName));
4335 }
4336 }
4337
Makoto Onuki2d895c32016-12-02 15:48:40 -08004338 @VisibleForTesting
4339 ShortcutRequestPinProcessor getShortcutRequestPinProcessorForTest() {
4340 return mShortcutRequestPinProcessor;
4341 }
4342
Makoto Onuki7001a612016-05-27 13:24:28 -07004343 /**
4344 * Control whether {@link #verifyStates} should be performed. We always perform it during unit
4345 * tests.
4346 */
4347 @VisibleForTesting
4348 boolean injectShouldPerformVerification() {
4349 return DEBUG;
4350 }
4351
4352 /**
4353 * Check various internal states and throws if there's any inconsistency.
4354 * This is normally only enabled during unit tests.
4355 */
4356 final void verifyStates() {
4357 if (injectShouldPerformVerification()) {
4358 verifyStatesInner();
4359 }
4360 }
4361
Makoto Onukib08790c2016-06-23 14:05:46 -07004362 private final void verifyStatesForce() {
4363 verifyStatesInner();
4364 }
4365
Makoto Onuki7001a612016-05-27 13:24:28 -07004366 private void verifyStatesInner() {
Makoto Onuki10305202016-07-14 18:14:08 -07004367 synchronized (mLock) {
Makoto Onuki7001a612016-05-27 13:24:28 -07004368 forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
4369 }
4370 }
Makoto Onuki475c3652017-05-08 14:29:03 -07004371
4372 @VisibleForTesting
4373 void waitForBitmapSavesForTest() {
4374 synchronized (mLock) {
4375 mShortcutBitmapSaver.waitForAllSavesLocked();
4376 }
4377 }
Makoto Onuki41066a62016-03-09 16:18:44 -08004378}