blob: 505e4ee605292c1993a6841d7649ac4a7e9c8ac2 [file] [log] [blame]
Makoto Onuki31459242016-03-22 11:12:18 -07001/*
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
18import android.annotation.NonNull;
Makoto Onukic51b2872016-05-04 15:24:50 -070019import android.annotation.Nullable;
Makoto Onuki31459242016-03-22 11:12:18 -070020import android.annotation.UserIdInt;
21import android.content.ComponentName;
Makoto Onuki4e6cef42016-07-13 16:14:01 -070022import android.content.pm.ShortcutManager;
23import android.text.TextUtils;
Makoto Onuki0033b2a2016-04-14 17:19:16 -070024import android.text.format.Formatter;
Makoto Onuki31459242016-03-22 11:12:18 -070025import android.util.ArrayMap;
Makoto Onukifc4cf2d2016-08-24 11:10:26 -070026import android.util.Log;
Makoto Onuki0acbb142016-03-22 17:02:57 -070027import android.util.Slog;
Makoto Onuki31459242016-03-22 11:12:18 -070028
Makoto Onuki4d36b3a2016-04-27 12:00:17 -070029import com.android.internal.annotations.VisibleForTesting;
Makoto Onukid99c6f02016-03-28 11:02:54 -070030import com.android.internal.util.Preconditions;
Makoto Onuki20b82212017-10-04 15:03:50 -070031import com.android.server.pm.ShortcutService.DumpFilter;
Makoto Onukifc4cf2d2016-08-24 11:10:26 -070032import com.android.server.pm.ShortcutService.InvalidFileFormatException;
Makoto Onukid99c6f02016-03-28 11:02:54 -070033
Makoto Onuki76269922016-07-15 14:58:54 -070034import org.json.JSONArray;
35import org.json.JSONException;
36import org.json.JSONObject;
Makoto Onuki31459242016-03-22 11:12:18 -070037import org.xmlpull.v1.XmlPullParser;
38import org.xmlpull.v1.XmlPullParserException;
39import org.xmlpull.v1.XmlSerializer;
40
Makoto Onuki0033b2a2016-04-14 17:19:16 -070041import java.io.File;
Makoto Onuki31459242016-03-22 11:12:18 -070042import java.io.IOException;
43import java.io.PrintWriter;
Narayan Kamath607223f2018-02-19 14:09:02 +000044import java.util.Objects;
Makoto Onuki9da23fc2016-03-29 11:14:42 -070045import java.util.function.Consumer;
Makoto Onuki31459242016-03-22 11:12:18 -070046
47/**
48 * User information used by {@link ShortcutService}.
Makoto Onuki22fcc682016-05-17 14:52:19 -070049 *
50 * All methods should be guarded by {@code #mService.mLock}.
Makoto Onuki31459242016-03-22 11:12:18 -070051 */
52class ShortcutUser {
53 private static final String TAG = ShortcutService.TAG;
54
55 static final String TAG_ROOT = "user";
56 private static final String TAG_LAUNCHER = "launcher";
57
58 private static final String ATTR_VALUE = "value";
Makoto Onuki4e6cef42016-07-13 16:14:01 -070059 private static final String ATTR_KNOWN_LOCALES = "locales";
Makoto Onuki4dd032d2016-08-02 11:39:19 -070060
61 // Suffix "2" was added to force rescan all packages after the next OTA.
62 private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
Makoto Onuki33663282016-08-22 16:19:04 -070063 private static final String ATTR_LAST_APP_SCAN_OS_FINGERPRINT = "last-app-scan-fp";
Makoto Onukie3fffa92018-02-28 16:25:40 -080064 private static final String ATTR_RESTORE_SOURCE_FINGERPRINT = "restore-from-fp";
Makoto Onuki76269922016-07-15 14:58:54 -070065 private static final String KEY_USER_ID = "userId";
66 private static final String KEY_LAUNCHERS = "launchers";
67 private static final String KEY_PACKAGES = "packages";
Makoto Onuki31459242016-03-22 11:12:18 -070068
Makoto Onukid99c6f02016-03-28 11:02:54 -070069 static final class PackageWithUser {
70 final int userId;
71 final String packageName;
72
73 private PackageWithUser(int userId, String packageName) {
74 this.userId = userId;
75 this.packageName = Preconditions.checkNotNull(packageName);
76 }
77
Makoto Onuki2e210c42016-03-30 08:30:36 -070078 public static PackageWithUser of(int userId, String packageName) {
79 return new PackageWithUser(userId, packageName);
Makoto Onukid99c6f02016-03-28 11:02:54 -070080 }
81
Makoto Onuki9da23fc2016-03-29 11:14:42 -070082 public static PackageWithUser of(ShortcutPackageItem spi) {
83 return new PackageWithUser(spi.getPackageUserId(), spi.getPackageName());
84 }
85
Makoto Onukid99c6f02016-03-28 11:02:54 -070086 @Override
87 public int hashCode() {
88 return packageName.hashCode() ^ userId;
89 }
90
91 @Override
92 public boolean equals(Object obj) {
93 if (!(obj instanceof PackageWithUser)) {
94 return false;
95 }
96 final PackageWithUser that = (PackageWithUser) obj;
97
98 return userId == that.userId && packageName.equals(that.packageName);
99 }
100
101 @Override
102 public String toString() {
Makoto Onukib08790c2016-06-23 14:05:46 -0700103 return String.format("[Package: %d, %s]", userId, packageName);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700104 }
105 }
106
Makoto Onukic51b2872016-05-04 15:24:50 -0700107 final ShortcutService mService;
108
Makoto Onuki31459242016-03-22 11:12:18 -0700109 @UserIdInt
Makoto Onuki2e210c42016-03-30 08:30:36 -0700110 private final int mUserId;
Makoto Onuki31459242016-03-22 11:12:18 -0700111
112 private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>();
113
Makoto Onukid99c6f02016-03-28 11:02:54 -0700114 private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
Makoto Onuki31459242016-03-22 11:12:18 -0700115
Makoto Onuki10305202016-07-14 18:14:08 -0700116 /**
117 * Last known launcher. It's used when the default launcher isn't set in PM -- i.e.
118 * when getHomeActivitiesAsUser() return null. We need it so that in this situation the
119 * previously default launcher can still access shortcuts.
120 */
121 private ComponentName mLastKnownLauncher;
122
123 /** In-memory-cached default launcher. */
124 private ComponentName mCachedLauncher;
Makoto Onuki31459242016-03-22 11:12:18 -0700125
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700126 private String mKnownLocales;
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700127
Makoto Onuki6dd9fb72016-06-01 13:55:54 -0700128 private long mLastAppScanTime;
129
Makoto Onuki33663282016-08-22 16:19:04 -0700130 private String mLastAppScanOsFingerprint;
Makoto Onukie3fffa92018-02-28 16:25:40 -0800131 private String mRestoreFromOsFingerprint;
Makoto Onuki33663282016-08-22 16:19:04 -0700132
Makoto Onukic51b2872016-05-04 15:24:50 -0700133 public ShortcutUser(ShortcutService service, int userId) {
134 mService = service;
Makoto Onuki31459242016-03-22 11:12:18 -0700135 mUserId = userId;
136 }
137
Makoto Onuki2e210c42016-03-30 08:30:36 -0700138 public int getUserId() {
139 return mUserId;
140 }
141
Makoto Onuki6dd9fb72016-06-01 13:55:54 -0700142 public long getLastAppScanTime() {
143 return mLastAppScanTime;
144 }
145
146 public void setLastAppScanTime(long lastAppScanTime) {
147 mLastAppScanTime = lastAppScanTime;
148 }
149
Makoto Onuki33663282016-08-22 16:19:04 -0700150 public String getLastAppScanOsFingerprint() {
151 return mLastAppScanOsFingerprint;
152 }
153
154 public void setLastAppScanOsFingerprint(String lastAppScanOsFingerprint) {
155 mLastAppScanOsFingerprint = lastAppScanOsFingerprint;
156 }
157
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700158 // We don't expose this directly to non-test code because only ShortcutUser should add to/
159 // remove from it.
160 @VisibleForTesting
161 ArrayMap<String, ShortcutPackage> getAllPackagesForTest() {
Makoto Onuki31459242016-03-22 11:12:18 -0700162 return mPackages;
163 }
164
Makoto Onuki6c1dbd52016-05-02 15:19:32 -0700165 public boolean hasPackage(@NonNull String packageName) {
166 return mPackages.containsKey(packageName);
167 }
168
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700169 private void addPackage(@NonNull ShortcutPackage p) {
170 p.replaceUser(this);
171 mPackages.put(p.getPackageName(), p);
172 }
173
Makoto Onukic51b2872016-05-04 15:24:50 -0700174 public ShortcutPackage removePackage(@NonNull String packageName) {
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700175 final ShortcutPackage removed = mPackages.remove(packageName);
176
Makoto Onukic51b2872016-05-04 15:24:50 -0700177 mService.cleanupBitmapsForPackage(mUserId, packageName);
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700178
179 return removed;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700180 }
181
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700182 // We don't expose this directly to non-test code because only ShortcutUser should add to/
183 // remove from it.
184 @VisibleForTesting
185 ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchersForTest() {
Makoto Onuki31459242016-03-22 11:12:18 -0700186 return mLaunchers;
187 }
188
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700189 private void addLauncher(ShortcutLauncher launcher) {
190 launcher.replaceUser(this);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700191 mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(),
192 launcher.getPackageName()), launcher);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700193 }
194
Makoto Onukic51b2872016-05-04 15:24:50 -0700195 @Nullable
Makoto Onukid99c6f02016-03-28 11:02:54 -0700196 public ShortcutLauncher removeLauncher(
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700197 @UserIdInt int packageUserId, @NonNull String packageName) {
198 return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
Makoto Onukid99c6f02016-03-28 11:02:54 -0700199 }
200
Makoto Onukic51b2872016-05-04 15:24:50 -0700201 @Nullable
202 public ShortcutPackage getPackageShortcutsIfExists(@NonNull String packageName) {
203 final ShortcutPackage ret = mPackages.get(packageName);
204 if (ret != null) {
205 ret.attemptToRestoreIfNeededAndSave();
Makoto Onuki31459242016-03-22 11:12:18 -0700206 }
207 return ret;
208 }
209
Makoto Onukic51b2872016-05-04 15:24:50 -0700210 @NonNull
211 public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
212 ShortcutPackage ret = getPackageShortcutsIfExists(packageName);
213 if (ret == null) {
214 ret = new ShortcutPackage(this, mUserId, packageName);
215 mPackages.put(packageName, ret);
216 }
217 return ret;
218 }
219
220 @NonNull
221 public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName,
Makoto Onukid99c6f02016-03-28 11:02:54 -0700222 @UserIdInt int launcherUserId) {
223 final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
224 ShortcutLauncher ret = mLaunchers.get(key);
Makoto Onuki31459242016-03-22 11:12:18 -0700225 if (ret == null) {
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700226 ret = new ShortcutLauncher(this, mUserId, packageName, launcherUserId);
Makoto Onukid99c6f02016-03-28 11:02:54 -0700227 mLaunchers.put(key, ret);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700228 } else {
Makoto Onukic51b2872016-05-04 15:24:50 -0700229 ret.attemptToRestoreIfNeededAndSave();
Makoto Onuki31459242016-03-22 11:12:18 -0700230 }
231 return ret;
232 }
233
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700234 public void forAllPackages(Consumer<? super ShortcutPackage> callback) {
235 final int size = mPackages.size();
236 for (int i = 0; i < size; i++) {
237 callback.accept(mPackages.valueAt(i));
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700238 }
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700239 }
240
241 public void forAllLaunchers(Consumer<? super ShortcutLauncher> callback) {
242 final int size = mLaunchers.size();
243 for (int i = 0; i < size; i++) {
244 callback.accept(mLaunchers.valueAt(i));
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700245 }
246 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700247
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700248 public void forAllPackageItems(Consumer<? super ShortcutPackageItem> callback) {
249 forAllLaunchers(callback);
250 forAllPackages(callback);
251 }
252
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700253 public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId,
254 Consumer<ShortcutPackageItem> callback) {
255 forAllPackageItems(spi -> {
256 if ((spi.getPackageUserId() == packageUserId)
257 && spi.getPackageName().equals(packageName)) {
258 callback.accept(spi);
259 }
260 });
Makoto Onuki0acbb142016-03-22 17:02:57 -0700261 }
262
Makoto Onuki39686e82016-04-13 18:03:00 -0700263 /**
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700264 * Must be called at any entry points on {@link ShortcutManager} APIs to make sure the
265 * information on the package is up-to-date.
266 *
267 * We use broadcasts to handle locale changes and package changes, but because broadcasts
268 * are asynchronous, there's a chance a publisher calls getXxxShortcuts() after a certain event
269 * (e.g. system locale change) but shortcut manager hasn't finished processing the broadcast.
270 *
271 * So we call this method at all entry points from publishers to make sure we update all
272 * relevant information.
273 *
274 * Similar inconsistencies can happen when the launcher fetches shortcut information, but
275 * that's a less of an issue because for the launcher we report shortcut changes with
276 * callbacks.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700277 */
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700278 public void onCalledByPublisher(@NonNull String packageName) {
279 detectLocaleChange();
280 rescanPackageIfNeeded(packageName, /*forceRescan=*/ false);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700281 }
282
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700283 private String getKnownLocales() {
284 if (TextUtils.isEmpty(mKnownLocales)) {
285 mKnownLocales = mService.injectGetLocaleTagsForUser(mUserId);
286 mService.scheduleSaveUser(mUserId);
287 }
288 return mKnownLocales;
289 }
290
291 /**
292 * Check to see if the system locale has changed, and if so, reset throttling
293 * and update resource strings.
294 */
295 public void detectLocaleChange() {
296 final String currentLocales = mService.injectGetLocaleTagsForUser(mUserId);
297 if (getKnownLocales().equals(currentLocales)) {
298 return;
299 }
300 if (ShortcutService.DEBUG) {
301 Slog.d(TAG, "Locale changed from " + currentLocales + " to " + mKnownLocales
302 + " for user " + mUserId);
303 }
304 mKnownLocales = currentLocales;
305
306 forAllPackages(pkg -> {
307 pkg.resetRateLimiting();
308 pkg.resolveResourceStrings();
309 });
310
311 mService.scheduleSaveUser(mUserId);
312 }
313
314 public void rescanPackageIfNeeded(@NonNull String packageName, boolean forceRescan) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700315 final boolean isNewApp = !mPackages.containsKey(packageName);
316
317 final ShortcutPackage shortcutPackage = getPackageShortcuts(packageName);
318
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700319 if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700320 if (isNewApp) {
321 mPackages.remove(packageName);
322 }
Makoto Onuki39686e82016-04-13 18:03:00 -0700323 }
Makoto Onuki39686e82016-04-13 18:03:00 -0700324 }
325
Makoto Onuki2e210c42016-03-30 08:30:36 -0700326 public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName,
327 @UserIdInt int packageUserId) {
328 forPackageItem(packageName, packageUserId, spi -> {
Makoto Onukic51b2872016-05-04 15:24:50 -0700329 spi.attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -0700330 });
331 }
332
Makoto Onukic51b2872016-05-04 15:24:50 -0700333 public void saveToXml(XmlSerializer out, boolean forBackup)
Makoto Onuki0acbb142016-03-22 17:02:57 -0700334 throws IOException, XmlPullParserException {
Makoto Onuki31459242016-03-22 11:12:18 -0700335 out.startTag(null, TAG_ROOT);
336
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700337 if (!forBackup) {
338 // Don't have to back them up.
339 ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
340 ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
341 mLastAppScanTime);
342 ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
343 mLastAppScanOsFingerprint);
Makoto Onukie3fffa92018-02-28 16:25:40 -0800344 ShortcutService.writeAttr(out, ATTR_RESTORE_SOURCE_FINGERPRINT,
345 mRestoreFromOsFingerprint);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700346
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700347 ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
Makoto Onukie3fffa92018-02-28 16:25:40 -0800348 } else {
349 ShortcutService.writeAttr(out, ATTR_RESTORE_SOURCE_FINGERPRINT,
350 mService.injectBuildFingerprint());
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700351 }
Makoto Onuki31459242016-03-22 11:12:18 -0700352
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700353 // Can't use forEachPackageItem due to the checked exceptions.
Makoto Onuki0acbb142016-03-22 17:02:57 -0700354 {
355 final int size = mLaunchers.size();
356 for (int i = 0; i < size; i++) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700357 saveShortcutPackageItem(out, mLaunchers.valueAt(i), forBackup);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700358 }
359 }
360 {
361 final int size = mPackages.size();
362 for (int i = 0; i < size; i++) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700363 saveShortcutPackageItem(out, mPackages.valueAt(i), forBackup);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700364 }
Makoto Onuki31459242016-03-22 11:12:18 -0700365 }
366
367 out.endTag(null, TAG_ROOT);
368 }
369
Makoto Onukic51b2872016-05-04 15:24:50 -0700370 private void saveShortcutPackageItem(XmlSerializer out,
Makoto Onuki0acbb142016-03-22 17:02:57 -0700371 ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700372 if (forBackup) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700373 if (spi.getPackageUserId() != spi.getOwnerUserId()) {
374 return; // Don't save cross-user information.
375 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700376 }
377 spi.saveToXml(out, forBackup);
378 }
379
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700380 public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700381 boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
Makoto Onukic51b2872016-05-04 15:24:50 -0700382 final ShortcutUser ret = new ShortcutUser(s, userId);
Makoto Onuki31459242016-03-22 11:12:18 -0700383
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700384 try {
385 ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
386 ATTR_KNOWN_LOCALES);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700387
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700388 // If lastAppScanTime is in the future, that means the clock went backwards.
389 // Just scan all apps again.
390 final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
391 ATTR_LAST_APP_SCAN_TIME);
392 final long currentTime = s.injectCurrentTimeMillis();
393 ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
394 ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
395 ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
Makoto Onukie3fffa92018-02-28 16:25:40 -0800396 ret.mRestoreFromOsFingerprint = ShortcutService.parseStringAttribute(parser,
397 ATTR_RESTORE_SOURCE_FINGERPRINT);
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700398 final int outerDepth = parser.getDepth();
399 int type;
400 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
401 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
402 if (type != XmlPullParser.START_TAG) {
403 continue;
404 }
405 final int depth = parser.getDepth();
406 final String tag = parser.getName();
Makoto Onuki31459242016-03-22 11:12:18 -0700407
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700408 if (depth == outerDepth + 1) {
409 switch (tag) {
410 case TAG_LAUNCHER: {
411 ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
412 parser, ATTR_VALUE);
413 continue;
414 }
415 case ShortcutPackage.TAG_ROOT: {
416 final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
417 s, ret, parser, fromBackup);
Makoto Onuki31459242016-03-22 11:12:18 -0700418
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700419 // Don't use addShortcut(), we don't need to save the icon.
420 ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
421 continue;
422 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700423
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700424 case ShortcutLauncher.TAG_ROOT: {
425 ret.addLauncher(
426 ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
427 continue;
428 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700429 }
Makoto Onuki31459242016-03-22 11:12:18 -0700430 }
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700431 ShortcutService.warnForInvalidTag(depth, tag);
Makoto Onuki31459242016-03-22 11:12:18 -0700432 }
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700433 } catch (RuntimeException e) {
434 throw new ShortcutService.InvalidFileFormatException(
435 "Unable to parse file", e);
Makoto Onuki31459242016-03-22 11:12:18 -0700436 }
437 return ret;
438 }
439
Makoto Onuki10305202016-07-14 18:14:08 -0700440 public ComponentName getLastKnownLauncher() {
441 return mLastKnownLauncher;
Makoto Onuki31459242016-03-22 11:12:18 -0700442 }
443
Makoto Onuki10305202016-07-14 18:14:08 -0700444 public void setLauncher(ComponentName launcherComponent) {
445 setLauncher(launcherComponent, /* allowPurgeLastKnown */ false);
446 }
447
448 /** Clears the launcher information without clearing the last known one */
449 public void clearLauncher() {
450 setLauncher(null);
451 }
452
453 /**
454 * Clears the launcher information *with(* clearing the last known one; we do this witl
455 * "cmd shortcut clear-default-launcher".
456 */
457 public void forceClearLauncher() {
458 setLauncher(null, /* allowPurgeLastKnown */ true);
459 }
460
461 private void setLauncher(ComponentName launcherComponent, boolean allowPurgeLastKnown) {
462 mCachedLauncher = launcherComponent; // Always update the in-memory cache.
463
Narayan Kamath607223f2018-02-19 14:09:02 +0000464 if (Objects.equals(mLastKnownLauncher, launcherComponent)) {
Makoto Onuki31459242016-03-22 11:12:18 -0700465 return;
466 }
Makoto Onuki10305202016-07-14 18:14:08 -0700467 if (!allowPurgeLastKnown && launcherComponent == null) {
468 return;
469 }
470 mLastKnownLauncher = launcherComponent;
Makoto Onukic51b2872016-05-04 15:24:50 -0700471 mService.scheduleSaveUser(mUserId);
Makoto Onuki31459242016-03-22 11:12:18 -0700472 }
473
Makoto Onuki10305202016-07-14 18:14:08 -0700474 public ComponentName getCachedLauncher() {
475 return mCachedLauncher;
476 }
477
Makoto Onuki31459242016-03-22 11:12:18 -0700478 public void resetThrottling() {
479 for (int i = mPackages.size() - 1; i >= 0; i--) {
480 mPackages.valueAt(i).resetThrottling();
481 }
482 }
483
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700484 public void mergeRestoredFile(ShortcutUser restored) {
485 final ShortcutService s = mService;
486 // Note, a restore happens only at the end of setup wizard. At this point, no apps are
487 // installed from Play Store yet, but it's still possible that system apps have already
488 // published dynamic shortcuts, since some apps do so on BOOT_COMPLETED.
489 // When such a system app has allowbackup=true, then we go ahead and replace all existing
490 // shortcuts with the restored shortcuts. (Then we'll re-publish manifest shortcuts later
491 // in the call site.)
492 // When such a system app has allowbackup=false, then we'll keep the shortcuts that have
493 // already been published. So we selectively add restored ShortcutPackages here.
494 //
495 // The same logic applies to launchers, but since launchers shouldn't pin shortcuts
496 // without users interaction it's really not a big deal, so we just clear existing
497 // ShortcutLauncher instances in mLaunchers and add all the restored ones here.
498
Makoto Onuki50a320e2017-05-31 14:38:42 -0700499 int[] restoredLaunchers = new int[1];
500 int[] restoredPackages = new int[1];
501 int[] restoredShortcuts = new int[1];
502
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700503 mLaunchers.clear();
504 restored.forAllLaunchers(sl -> {
505 // If the app is already installed and allowbackup = false, then ignore the restored
506 // data.
507 if (s.isPackageInstalled(sl.getPackageName(), getUserId())
508 && !s.shouldBackupApp(sl.getPackageName(), getUserId())) {
509 return;
510 }
511 addLauncher(sl);
Makoto Onuki50a320e2017-05-31 14:38:42 -0700512 restoredLaunchers[0]++;
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700513 });
514 restored.forAllPackages(sp -> {
515 // If the app is already installed and allowbackup = false, then ignore the restored
516 // data.
517 if (s.isPackageInstalled(sp.getPackageName(), getUserId())
518 && !s.shouldBackupApp(sp.getPackageName(), getUserId())) {
519 return;
520 }
521
522 final ShortcutPackage previous = getPackageShortcutsIfExists(sp.getPackageName());
523 if (previous != null && previous.hasNonManifestShortcuts()) {
524 Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
525 + " Existing non-manifeset shortcuts will be overwritten.");
526 }
527 addPackage(sp);
Makoto Onuki50a320e2017-05-31 14:38:42 -0700528 restoredPackages[0]++;
529 restoredShortcuts[0] += sp.getShortcutCount();
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700530 });
531 // Empty the launchers and packages in restored to avoid accidentally using them.
532 restored.mLaunchers.clear();
533 restored.mPackages.clear();
Makoto Onuki50a320e2017-05-31 14:38:42 -0700534
Makoto Onukie3fffa92018-02-28 16:25:40 -0800535 mRestoreFromOsFingerprint = restored.mRestoreFromOsFingerprint;
536
Makoto Onuki50a320e2017-05-31 14:38:42 -0700537 Slog.i(TAG, "Restored: L=" + restoredLaunchers[0]
538 + " P=" + restoredPackages[0]
539 + " S=" + restoredShortcuts[0]);
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700540 }
541
Makoto Onuki20b82212017-10-04 15:03:50 -0700542 public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
543 if (filter.shouldDumpDetails()) {
544 pw.print(prefix);
545 pw.print("User: ");
546 pw.print(mUserId);
547 pw.print(" Known locales: ");
548 pw.print(mKnownLocales);
549 pw.print(" Last app scan: [");
550 pw.print(mLastAppScanTime);
551 pw.print("] ");
Makoto Onukie3fffa92018-02-28 16:25:40 -0800552 pw.println(ShortcutService.formatTime(mLastAppScanTime));
Makoto Onuki31459242016-03-22 11:12:18 -0700553
Makoto Onuki20b82212017-10-04 15:03:50 -0700554 prefix += prefix + " ";
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700555
Makoto Onuki20b82212017-10-04 15:03:50 -0700556 pw.print(prefix);
Makoto Onukie3fffa92018-02-28 16:25:40 -0800557 pw.print("Last app scan FP: ");
558 pw.println(mLastAppScanOsFingerprint);
559
560 pw.print(prefix);
561 pw.print("Restore from FP: ");
562 pw.print(mRestoreFromOsFingerprint);
563 pw.println();
564
565
566 pw.print(prefix);
Makoto Onuki20b82212017-10-04 15:03:50 -0700567 pw.print("Cached launcher: ");
568 pw.print(mCachedLauncher);
569 pw.println();
Makoto Onuki10305202016-07-14 18:14:08 -0700570
Makoto Onuki20b82212017-10-04 15:03:50 -0700571 pw.print(prefix);
572 pw.print("Last known launcher: ");
573 pw.print(mLastKnownLauncher);
574 pw.println();
575 }
Makoto Onuki31459242016-03-22 11:12:18 -0700576
577 for (int i = 0; i < mLaunchers.size(); i++) {
Makoto Onuki20b82212017-10-04 15:03:50 -0700578 ShortcutLauncher launcher = mLaunchers.valueAt(i);
579 if (filter.isPackageMatch(launcher.getPackageName())) {
580 launcher.dump(pw, prefix, filter);
581 }
Makoto Onuki31459242016-03-22 11:12:18 -0700582 }
583
584 for (int i = 0; i < mPackages.size(); i++) {
Makoto Onuki20b82212017-10-04 15:03:50 -0700585 ShortcutPackage pkg = mPackages.valueAt(i);
586 if (filter.isPackageMatch(pkg.getPackageName())) {
587 pkg.dump(pw, prefix, filter);
588 }
Makoto Onuki31459242016-03-22 11:12:18 -0700589 }
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700590
Makoto Onuki20b82212017-10-04 15:03:50 -0700591 if (filter.shouldDumpDetails()) {
592 pw.println();
593 pw.print(prefix);
594 pw.println("Bitmap directories: ");
595 dumpDirectorySize(pw, prefix + " ", mService.getUserBitmapFilePath(mUserId));
596 }
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700597 }
598
Makoto Onukic51b2872016-05-04 15:24:50 -0700599 private void dumpDirectorySize(@NonNull PrintWriter pw,
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700600 @NonNull String prefix, File path) {
601 int numFiles = 0;
602 long size = 0;
603 final File[] children = path.listFiles();
604 if (children != null) {
605 for (File child : path.listFiles()) {
606 if (child.isFile()) {
607 numFiles++;
608 size += child.length();
609 } else if (child.isDirectory()) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700610 dumpDirectorySize(pw, prefix + " ", child);
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700611 }
612 }
613 }
614 pw.print(prefix);
615 pw.print("Path: ");
616 pw.print(path.getName());
617 pw.print("/ has ");
618 pw.print(numFiles);
619 pw.print(" files, size=");
620 pw.print(size);
621 pw.print(" (");
Makoto Onukic51b2872016-05-04 15:24:50 -0700622 pw.print(Formatter.formatFileSize(mService.mContext, size));
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700623 pw.println(")");
Makoto Onuki31459242016-03-22 11:12:18 -0700624 }
Makoto Onuki76269922016-07-15 14:58:54 -0700625
626 public JSONObject dumpCheckin(boolean clear) throws JSONException {
627 final JSONObject result = new JSONObject();
628
629 result.put(KEY_USER_ID, mUserId);
630
631 {
632 final JSONArray launchers = new JSONArray();
633 for (int i = 0; i < mLaunchers.size(); i++) {
634 launchers.put(mLaunchers.valueAt(i).dumpCheckin(clear));
635 }
636 result.put(KEY_LAUNCHERS, launchers);
637 }
638
639 {
640 final JSONArray packages = new JSONArray();
641 for (int i = 0; i < mPackages.size(); i++) {
642 packages.put(mPackages.valueAt(i).dumpCheckin(clear));
643 }
644 result.put(KEY_PACKAGES, packages);
645 }
646
647 return result;
648 }
Makoto Onuki31459242016-03-22 11:12:18 -0700649}