blob: 1fd9b69e521d843abc0216871669b89c158cbe2d [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);
peter.zhang5fe382e2018-04-09 11:03:03 +0800297 if (!TextUtils.isEmpty(mKnownLocales) && mKnownLocales.equals(currentLocales)) {
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700298 return;
299 }
300 if (ShortcutService.DEBUG) {
peter.zhang5fe382e2018-04-09 11:03:03 +0800301 Slog.d(TAG, "Locale changed from " + mKnownLocales + " to " + currentLocales
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700302 + " for user " + mUserId);
303 }
peter.zhang5fe382e2018-04-09 11:03:03 +0800304
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700305 mKnownLocales = currentLocales;
306
307 forAllPackages(pkg -> {
308 pkg.resetRateLimiting();
309 pkg.resolveResourceStrings();
310 });
311
312 mService.scheduleSaveUser(mUserId);
313 }
314
315 public void rescanPackageIfNeeded(@NonNull String packageName, boolean forceRescan) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700316 final boolean isNewApp = !mPackages.containsKey(packageName);
317
318 final ShortcutPackage shortcutPackage = getPackageShortcuts(packageName);
319
Makoto Onuki4e6cef42016-07-13 16:14:01 -0700320 if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700321 if (isNewApp) {
322 mPackages.remove(packageName);
323 }
Makoto Onuki39686e82016-04-13 18:03:00 -0700324 }
Makoto Onuki39686e82016-04-13 18:03:00 -0700325 }
326
Makoto Onuki2e210c42016-03-30 08:30:36 -0700327 public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName,
328 @UserIdInt int packageUserId) {
329 forPackageItem(packageName, packageUserId, spi -> {
Makoto Onukic51b2872016-05-04 15:24:50 -0700330 spi.attemptToRestoreIfNeededAndSave();
Makoto Onuki2e210c42016-03-30 08:30:36 -0700331 });
332 }
333
Makoto Onukic51b2872016-05-04 15:24:50 -0700334 public void saveToXml(XmlSerializer out, boolean forBackup)
Makoto Onuki0acbb142016-03-22 17:02:57 -0700335 throws IOException, XmlPullParserException {
Makoto Onuki31459242016-03-22 11:12:18 -0700336 out.startTag(null, TAG_ROOT);
337
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700338 if (!forBackup) {
339 // Don't have to back them up.
340 ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
341 ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
342 mLastAppScanTime);
343 ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
344 mLastAppScanOsFingerprint);
Makoto Onukie3fffa92018-02-28 16:25:40 -0800345 ShortcutService.writeAttr(out, ATTR_RESTORE_SOURCE_FINGERPRINT,
346 mRestoreFromOsFingerprint);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700347
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700348 ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
Makoto Onukie3fffa92018-02-28 16:25:40 -0800349 } else {
350 ShortcutService.writeAttr(out, ATTR_RESTORE_SOURCE_FINGERPRINT,
351 mService.injectBuildFingerprint());
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700352 }
Makoto Onuki31459242016-03-22 11:12:18 -0700353
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700354 // Can't use forEachPackageItem due to the checked exceptions.
Makoto Onuki0acbb142016-03-22 17:02:57 -0700355 {
356 final int size = mLaunchers.size();
357 for (int i = 0; i < size; i++) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700358 saveShortcutPackageItem(out, mLaunchers.valueAt(i), forBackup);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700359 }
360 }
361 {
362 final int size = mPackages.size();
363 for (int i = 0; i < size; i++) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700364 saveShortcutPackageItem(out, mPackages.valueAt(i), forBackup);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700365 }
Makoto Onuki31459242016-03-22 11:12:18 -0700366 }
367
368 out.endTag(null, TAG_ROOT);
369 }
370
Makoto Onukic51b2872016-05-04 15:24:50 -0700371 private void saveShortcutPackageItem(XmlSerializer out,
Makoto Onuki0acbb142016-03-22 17:02:57 -0700372 ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700373 if (forBackup) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700374 if (spi.getPackageUserId() != spi.getOwnerUserId()) {
375 return; // Don't save cross-user information.
376 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700377 }
378 spi.saveToXml(out, forBackup);
379 }
380
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700381 public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700382 boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
Makoto Onukic51b2872016-05-04 15:24:50 -0700383 final ShortcutUser ret = new ShortcutUser(s, userId);
Makoto Onuki31459242016-03-22 11:12:18 -0700384
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700385 try {
386 ret.mKnownLocales = ShortcutService.parseStringAttribute(parser,
387 ATTR_KNOWN_LOCALES);
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700388
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700389 // If lastAppScanTime is in the future, that means the clock went backwards.
390 // Just scan all apps again.
391 final long lastAppScanTime = ShortcutService.parseLongAttribute(parser,
392 ATTR_LAST_APP_SCAN_TIME);
393 final long currentTime = s.injectCurrentTimeMillis();
394 ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
395 ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
396 ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
Makoto Onukie3fffa92018-02-28 16:25:40 -0800397 ret.mRestoreFromOsFingerprint = ShortcutService.parseStringAttribute(parser,
398 ATTR_RESTORE_SOURCE_FINGERPRINT);
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700399 final int outerDepth = parser.getDepth();
400 int type;
401 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
402 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
403 if (type != XmlPullParser.START_TAG) {
404 continue;
405 }
406 final int depth = parser.getDepth();
407 final String tag = parser.getName();
Makoto Onuki31459242016-03-22 11:12:18 -0700408
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700409 if (depth == outerDepth + 1) {
410 switch (tag) {
411 case TAG_LAUNCHER: {
412 ret.mLastKnownLauncher = ShortcutService.parseComponentNameAttribute(
413 parser, ATTR_VALUE);
414 continue;
415 }
416 case ShortcutPackage.TAG_ROOT: {
417 final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
418 s, ret, parser, fromBackup);
Makoto Onuki31459242016-03-22 11:12:18 -0700419
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700420 // Don't use addShortcut(), we don't need to save the icon.
421 ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
422 continue;
423 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700424
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700425 case ShortcutLauncher.TAG_ROOT: {
426 ret.addLauncher(
427 ShortcutLauncher.loadFromXml(parser, ret, userId, fromBackup));
428 continue;
429 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700430 }
Makoto Onuki31459242016-03-22 11:12:18 -0700431 }
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700432 ShortcutService.warnForInvalidTag(depth, tag);
Makoto Onuki31459242016-03-22 11:12:18 -0700433 }
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700434 } catch (RuntimeException e) {
435 throw new ShortcutService.InvalidFileFormatException(
436 "Unable to parse file", e);
Makoto Onuki31459242016-03-22 11:12:18 -0700437 }
438 return ret;
439 }
440
Makoto Onuki10305202016-07-14 18:14:08 -0700441 public ComponentName getLastKnownLauncher() {
442 return mLastKnownLauncher;
Makoto Onuki31459242016-03-22 11:12:18 -0700443 }
444
Makoto Onuki10305202016-07-14 18:14:08 -0700445 public void setLauncher(ComponentName launcherComponent) {
446 setLauncher(launcherComponent, /* allowPurgeLastKnown */ false);
447 }
448
449 /** Clears the launcher information without clearing the last known one */
450 public void clearLauncher() {
451 setLauncher(null);
452 }
453
454 /**
455 * Clears the launcher information *with(* clearing the last known one; we do this witl
456 * "cmd shortcut clear-default-launcher".
457 */
458 public void forceClearLauncher() {
459 setLauncher(null, /* allowPurgeLastKnown */ true);
460 }
461
462 private void setLauncher(ComponentName launcherComponent, boolean allowPurgeLastKnown) {
463 mCachedLauncher = launcherComponent; // Always update the in-memory cache.
464
Narayan Kamath607223f2018-02-19 14:09:02 +0000465 if (Objects.equals(mLastKnownLauncher, launcherComponent)) {
Makoto Onuki31459242016-03-22 11:12:18 -0700466 return;
467 }
Makoto Onuki10305202016-07-14 18:14:08 -0700468 if (!allowPurgeLastKnown && launcherComponent == null) {
469 return;
470 }
471 mLastKnownLauncher = launcherComponent;
Makoto Onukic51b2872016-05-04 15:24:50 -0700472 mService.scheduleSaveUser(mUserId);
Makoto Onuki31459242016-03-22 11:12:18 -0700473 }
474
Makoto Onuki10305202016-07-14 18:14:08 -0700475 public ComponentName getCachedLauncher() {
476 return mCachedLauncher;
477 }
478
Makoto Onuki31459242016-03-22 11:12:18 -0700479 public void resetThrottling() {
480 for (int i = mPackages.size() - 1; i >= 0; i--) {
481 mPackages.valueAt(i).resetThrottling();
482 }
483 }
484
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700485 public void mergeRestoredFile(ShortcutUser restored) {
486 final ShortcutService s = mService;
487 // Note, a restore happens only at the end of setup wizard. At this point, no apps are
488 // installed from Play Store yet, but it's still possible that system apps have already
489 // published dynamic shortcuts, since some apps do so on BOOT_COMPLETED.
490 // When such a system app has allowbackup=true, then we go ahead and replace all existing
491 // shortcuts with the restored shortcuts. (Then we'll re-publish manifest shortcuts later
492 // in the call site.)
493 // When such a system app has allowbackup=false, then we'll keep the shortcuts that have
494 // already been published. So we selectively add restored ShortcutPackages here.
495 //
496 // The same logic applies to launchers, but since launchers shouldn't pin shortcuts
497 // without users interaction it's really not a big deal, so we just clear existing
498 // ShortcutLauncher instances in mLaunchers and add all the restored ones here.
499
Makoto Onuki50a320e2017-05-31 14:38:42 -0700500 int[] restoredLaunchers = new int[1];
501 int[] restoredPackages = new int[1];
502 int[] restoredShortcuts = new int[1];
503
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700504 mLaunchers.clear();
505 restored.forAllLaunchers(sl -> {
506 // If the app is already installed and allowbackup = false, then ignore the restored
507 // data.
508 if (s.isPackageInstalled(sl.getPackageName(), getUserId())
509 && !s.shouldBackupApp(sl.getPackageName(), getUserId())) {
510 return;
511 }
512 addLauncher(sl);
Makoto Onuki50a320e2017-05-31 14:38:42 -0700513 restoredLaunchers[0]++;
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700514 });
515 restored.forAllPackages(sp -> {
516 // If the app is already installed and allowbackup = false, then ignore the restored
517 // data.
518 if (s.isPackageInstalled(sp.getPackageName(), getUserId())
519 && !s.shouldBackupApp(sp.getPackageName(), getUserId())) {
520 return;
521 }
522
523 final ShortcutPackage previous = getPackageShortcutsIfExists(sp.getPackageName());
524 if (previous != null && previous.hasNonManifestShortcuts()) {
525 Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
526 + " Existing non-manifeset shortcuts will be overwritten.");
527 }
528 addPackage(sp);
Makoto Onuki50a320e2017-05-31 14:38:42 -0700529 restoredPackages[0]++;
530 restoredShortcuts[0] += sp.getShortcutCount();
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700531 });
532 // Empty the launchers and packages in restored to avoid accidentally using them.
533 restored.mLaunchers.clear();
534 restored.mPackages.clear();
Makoto Onuki50a320e2017-05-31 14:38:42 -0700535
Makoto Onukie3fffa92018-02-28 16:25:40 -0800536 mRestoreFromOsFingerprint = restored.mRestoreFromOsFingerprint;
537
Makoto Onuki50a320e2017-05-31 14:38:42 -0700538 Slog.i(TAG, "Restored: L=" + restoredLaunchers[0]
539 + " P=" + restoredPackages[0]
540 + " S=" + restoredShortcuts[0]);
Makoto Onukifc4cf2d2016-08-24 11:10:26 -0700541 }
542
Makoto Onuki20b82212017-10-04 15:03:50 -0700543 public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
544 if (filter.shouldDumpDetails()) {
545 pw.print(prefix);
546 pw.print("User: ");
547 pw.print(mUserId);
548 pw.print(" Known locales: ");
549 pw.print(mKnownLocales);
550 pw.print(" Last app scan: [");
551 pw.print(mLastAppScanTime);
552 pw.print("] ");
Makoto Onukie3fffa92018-02-28 16:25:40 -0800553 pw.println(ShortcutService.formatTime(mLastAppScanTime));
Makoto Onuki31459242016-03-22 11:12:18 -0700554
Makoto Onuki20b82212017-10-04 15:03:50 -0700555 prefix += prefix + " ";
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700556
Makoto Onuki20b82212017-10-04 15:03:50 -0700557 pw.print(prefix);
Makoto Onukie3fffa92018-02-28 16:25:40 -0800558 pw.print("Last app scan FP: ");
559 pw.println(mLastAppScanOsFingerprint);
560
561 pw.print(prefix);
562 pw.print("Restore from FP: ");
563 pw.print(mRestoreFromOsFingerprint);
564 pw.println();
565
566
567 pw.print(prefix);
Makoto Onuki20b82212017-10-04 15:03:50 -0700568 pw.print("Cached launcher: ");
569 pw.print(mCachedLauncher);
570 pw.println();
Makoto Onuki10305202016-07-14 18:14:08 -0700571
Makoto Onuki20b82212017-10-04 15:03:50 -0700572 pw.print(prefix);
573 pw.print("Last known launcher: ");
574 pw.print(mLastKnownLauncher);
575 pw.println();
576 }
Makoto Onuki31459242016-03-22 11:12:18 -0700577
578 for (int i = 0; i < mLaunchers.size(); i++) {
Makoto Onuki20b82212017-10-04 15:03:50 -0700579 ShortcutLauncher launcher = mLaunchers.valueAt(i);
580 if (filter.isPackageMatch(launcher.getPackageName())) {
581 launcher.dump(pw, prefix, filter);
582 }
Makoto Onuki31459242016-03-22 11:12:18 -0700583 }
584
585 for (int i = 0; i < mPackages.size(); i++) {
Makoto Onuki20b82212017-10-04 15:03:50 -0700586 ShortcutPackage pkg = mPackages.valueAt(i);
587 if (filter.isPackageMatch(pkg.getPackageName())) {
588 pkg.dump(pw, prefix, filter);
589 }
Makoto Onuki31459242016-03-22 11:12:18 -0700590 }
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700591
Makoto Onuki20b82212017-10-04 15:03:50 -0700592 if (filter.shouldDumpDetails()) {
593 pw.println();
594 pw.print(prefix);
595 pw.println("Bitmap directories: ");
596 dumpDirectorySize(pw, prefix + " ", mService.getUserBitmapFilePath(mUserId));
597 }
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700598 }
599
Makoto Onukic51b2872016-05-04 15:24:50 -0700600 private void dumpDirectorySize(@NonNull PrintWriter pw,
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700601 @NonNull String prefix, File path) {
602 int numFiles = 0;
603 long size = 0;
604 final File[] children = path.listFiles();
605 if (children != null) {
606 for (File child : path.listFiles()) {
607 if (child.isFile()) {
608 numFiles++;
609 size += child.length();
610 } else if (child.isDirectory()) {
Makoto Onukic51b2872016-05-04 15:24:50 -0700611 dumpDirectorySize(pw, prefix + " ", child);
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700612 }
613 }
614 }
615 pw.print(prefix);
616 pw.print("Path: ");
617 pw.print(path.getName());
618 pw.print("/ has ");
619 pw.print(numFiles);
620 pw.print(" files, size=");
621 pw.print(size);
622 pw.print(" (");
Makoto Onukic51b2872016-05-04 15:24:50 -0700623 pw.print(Formatter.formatFileSize(mService.mContext, size));
Makoto Onuki0033b2a2016-04-14 17:19:16 -0700624 pw.println(")");
Makoto Onuki31459242016-03-22 11:12:18 -0700625 }
Makoto Onuki76269922016-07-15 14:58:54 -0700626
627 public JSONObject dumpCheckin(boolean clear) throws JSONException {
628 final JSONObject result = new JSONObject();
629
630 result.put(KEY_USER_ID, mUserId);
631
632 {
633 final JSONArray launchers = new JSONArray();
634 for (int i = 0; i < mLaunchers.size(); i++) {
635 launchers.put(mLaunchers.valueAt(i).dumpCheckin(clear));
636 }
637 result.put(KEY_LAUNCHERS, launchers);
638 }
639
640 {
641 final JSONArray packages = new JSONArray();
642 for (int i = 0; i < mPackages.size(); i++) {
643 packages.put(mPackages.valueAt(i).dumpCheckin(clear));
644 }
645 result.put(KEY_PACKAGES, packages);
646 }
647
648 return result;
649 }
Makoto Onuki31459242016-03-22 11:12:18 -0700650}