ShortcutService.java revision 20c95f854e54b71caa49f0efe07d47d1e6afd435
16f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki/* 26f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Copyright (C) 2016 The Android Open Source Project 36f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * 46f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 56f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * you may not use this file except in compliance with the License. 66f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * You may obtain a copy of the License at 76f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * 86f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 96f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * 106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Unless required by applicable law or agreed to in writing, software 116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * See the License for the specific language governing permissions and 146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * limitations under the License. 156f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 166f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukipackage com.android.server.pm; 176f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 186f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.annotation.NonNull; 196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.annotation.Nullable; 206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.annotation.UserIdInt; 215504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport android.app.ActivityManager; 224d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onukiimport android.app.ActivityManagerNative; 230acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport android.app.AppGlobals; 244d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onukiimport android.app.IUidObserver; 256f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.ComponentName; 266f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.Context; 276f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.Intent; 280acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport android.content.pm.ApplicationInfo; 290acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport android.content.pm.IPackageManager; 306f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.pm.IShortcutService; 316f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.pm.LauncherApps; 326f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.pm.LauncherApps.ShortcutQuery; 330acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport android.content.pm.PackageInfo; 346f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.pm.PackageManager; 3520c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onukiimport android.content.pm.PackageManager.NameNotFoundException; 362d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onukiimport android.content.pm.PackageManagerInternal; 376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.pm.ParceledListSlice; 382d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onukiimport android.content.pm.ResolveInfo; 396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.pm.ShortcutInfo; 406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.pm.ShortcutServiceInternal; 416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; 425504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport android.graphics.Bitmap; 435504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport android.graphics.Bitmap.CompressFormat; 445504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport android.graphics.Canvas; 455504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport android.graphics.RectF; 466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.graphics.drawable.Icon; 476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.Binder; 486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.Environment; 492e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onukiimport android.os.FileUtils; 506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.Handler; 51aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onukiimport android.os.Looper; 525504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport android.os.ParcelFileDescriptor; 536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.PersistableBundle; 546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.Process; 556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.RemoteException; 566f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.ResultReceiver; 575504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport android.os.SELinux; 586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.ShellCommand; 594d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onukiimport android.os.SystemClock; 606f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.os.UserHandle; 61cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onukiimport android.os.UserManager; 626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.text.TextUtils; 636f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.text.format.Time; 646f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.util.ArraySet; 656f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.util.AtomicFile; 664362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onukiimport android.util.KeyValueListParser; 676f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.util.Slog; 686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.util.SparseArray; 694d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onukiimport android.util.SparseIntArray; 704d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onukiimport android.util.SparseLongArray; 715504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport android.util.TypedValue; 726f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport android.util.Xml; 736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport com.android.internal.annotations.GuardedBy; 756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport com.android.internal.annotations.VisibleForTesting; 76cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onukiimport com.android.internal.content.PackageMonitor; 776f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport com.android.internal.os.BackgroundThread; 786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport com.android.internal.util.FastXmlSerializer; 796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport com.android.internal.util.Preconditions; 806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport com.android.server.LocalServices; 816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport com.android.server.SystemService; 82d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onukiimport com.android.server.pm.ShortcutUser.PackageWithUser; 836f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 846f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport libcore.io.IoUtils; 856f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 866f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport org.xmlpull.v1.XmlPullParser; 876f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport org.xmlpull.v1.XmlPullParserException; 886f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport org.xmlpull.v1.XmlSerializer; 896f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 909da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onukiimport java.io.BufferedInputStream; 919da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onukiimport java.io.BufferedOutputStream; 929da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onukiimport java.io.ByteArrayInputStream; 939da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onukiimport java.io.ByteArrayOutputStream; 946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.io.File; 956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.io.FileDescriptor; 966f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.io.FileInputStream; 976f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.io.FileNotFoundException; 986f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.io.FileOutputStream; 996f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.io.IOException; 1005504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onukiimport java.io.InputStream; 1019da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onukiimport java.io.OutputStream; 1026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.io.PrintWriter; 1036f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.net.URISyntaxException; 1046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.nio.charset.StandardCharsets; 1056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.util.ArrayList; 1066f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.util.List; 107c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onukiimport java.util.concurrent.atomic.AtomicBoolean; 1084d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onukiimport java.util.concurrent.atomic.AtomicLong; 1092e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onukiimport java.util.function.Consumer; 1106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukiimport java.util.function.Predicate; 1116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki/** 1136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * TODO: 11420c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * - Manifest shortcuts. 1156f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * 11620c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * - Implement disableShortcuts(). 11720c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * 11820c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * - Implement reportShortcutUsed(). 11920c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * 12020c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * - Ranks should be recalculated after each update. 1216f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * 12220c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * - When the system locale changes, update timestamps for shortcuts with string resources, 12320c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * and notify the launcher. 1246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * 12520c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki * - Default launcher check does take a few ms. Worth caching. 1265504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki * 127aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki * - Detect when already registered instances are passed to APIs again, which might break 128aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki * internal bitmap handling. 1292e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki * 1302e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki * - Add more call stats. 1316f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 1326f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onukipublic class ShortcutService extends IShortcutService.Stub { 1335504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki static final String TAG = "ShortcutService"; 1346f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1354554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki static final boolean DEBUG = false; // STOPSHIP if true 13641066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static final boolean DEBUG_LOAD = false; // STOPSHIP if true 1374d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true 1386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1394362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 1404d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day 1414362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 1424362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 1434d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki static final int DEFAULT_MAX_UPDATES_PER_INTERVAL = 10; 1444362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 1454362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 1464362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5; 1474362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 1484362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 1494362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96; 1504362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 1514362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 1524362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki static final int DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP = 48; 1534362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 1544362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 1554362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki static final String DEFAULT_ICON_PERSIST_FORMAT = CompressFormat.PNG.name(); 1564362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 1574362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 1584362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki static final int DEFAULT_ICON_PERSIST_QUALITY = 100; 1596f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 160aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki @VisibleForTesting 161aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki static final int DEFAULT_SAVE_DELAY_MS = 3000; 1626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1636f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 1646f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki static final String FILENAME_BASE_STATE = "shortcut_service.xml"; 1656f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1666f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 1676f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki static final String DIRECTORY_PER_USER = "shortcut_service"; 1686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 1706f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki static final String FILENAME_USER_PACKAGES = "shortcuts.xml"; 1716f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1725504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki static final String DIRECTORY_BITMAPS = "bitmaps"; 1736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 174aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki private static final String TAG_ROOT = "root"; 175aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki private static final String TAG_LAST_RESET_TIME = "last_reset_time"; 1764d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki private static final String TAG_LOCALE_CHANGE_SEQUENCE_NUMBER = "locale_seq_no"; 177aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 178aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki private static final String ATTR_VALUE = "value"; 1796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1804362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 1814362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki interface ConfigConstants { 1824362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 183aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki * Key name for the save delay, in milliseconds. (int) 184aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki */ 185aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki String KEY_SAVE_DELAY_MILLIS = "save_delay_ms"; 186aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 187aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki /** 1884362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki * Key name for the throttling reset interval, in seconds. (long) 1894362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 1904362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki String KEY_RESET_INTERVAL_SEC = "reset_interval_sec"; 1914362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 1924362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 1934362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki * Key name for the max number of modifying API calls per app for every interval. (int) 1944362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 195b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki String KEY_MAX_UPDATES_PER_INTERVAL = "max_updates_per_interval"; 1964362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 1974362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 1984362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki * Key name for the max icon dimensions in DP, for non-low-memory devices. 1994362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 2004362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki String KEY_MAX_ICON_DIMENSION_DP = "max_icon_dimension_dp"; 2014362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 2024362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 2034362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki * Key name for the max icon dimensions in DP, for low-memory devices. 2044362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 2054362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki String KEY_MAX_ICON_DIMENSION_DP_LOWRAM = "max_icon_dimension_dp_lowram"; 2064362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 2074362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 2084362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki * Key name for the max dynamic shortcuts per app. (int) 2094362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 2104362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki String KEY_MAX_SHORTCUTS = "max_shortcuts"; 2114362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 2124362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 21341066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki * Key name for icon compression quality, 0-100. 2144362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 2154362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki String KEY_ICON_QUALITY = "icon_quality"; 2164362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 2174362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 2184362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki * Key name for icon compression format: "PNG", "JPEG" or "WEBP" 2194362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 2204362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki String KEY_ICON_FORMAT = "icon_format"; 2214362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 2224362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 22341066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki final Context mContext; 2246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2256f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private final Object mLock = new Object(); 2266f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2276f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private final Handler mHandler; 2286f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2296f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @GuardedBy("mLock") 2306f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private final ArrayList<ShortcutChangeListener> mListeners = new ArrayList<>(1); 2316f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2326f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @GuardedBy("mLock") 2336f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private long mRawLastResetTime; 2346f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2356f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 2363f4b1ca97ad7c31bdbe2ba29264841fb58683e81Makoto Onuki * User ID -> UserShortcuts 2376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 2386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @GuardedBy("mLock") 2393145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki private final SparseArray<ShortcutUser> mUsers = new SparseArray<>(); 2406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 2426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Max number of dynamic shortcuts that each application can have at a time. 2436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 2446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private int mMaxDynamicShortcuts; 2456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 247b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki * Max number of updating API calls that each application can make during the interval. 2486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 249b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki int mMaxUpdatesPerInterval; 2506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2516f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 2526f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Actual throttling-reset interval. By default it's a day. 2536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 2546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private long mResetInterval; 2556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 2565504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki /** 2575504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki * Icon max width/height in pixels. 2585504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki */ 2595504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki private int mMaxIconDimension; 2605504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 2614362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki private CompressFormat mIconPersistFormat; 2624362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki private int mIconPersistQuality; 2635504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 264aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki private int mSaveDelayMillis; 265aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 2660acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private final IPackageManager mIPackageManager; 2672d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private final PackageManagerInternal mPackageManagerInternal; 268cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki private final UserManager mUserManager; 2692d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 270aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki @GuardedBy("mLock") 2714d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki final SparseIntArray mUidState = new SparseIntArray(); 2724d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 2734d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @GuardedBy("mLock") 2744d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki final SparseLongArray mUidLastForegroundElapsedTime = new SparseLongArray(); 2754d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 2764d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @GuardedBy("mLock") 277aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki private List<Integer> mDirtyUserIds = new ArrayList<>(); 278aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 2794d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki /** 2804d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * A counter that increments every time the system locale changes. We keep track of it to reset 2814d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * throttling counters on the first call from each package after the last locale change. 2824d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * 2834d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * We need this mechanism because we can't do much in the locale change callback, which is 2844d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * {@link ShortcutServiceInternal#onSystemLocaleChangedNoLock()}. 2854d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki */ 2864d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki private final AtomicLong mLocaleChangeSequenceNumber = new AtomicLong(); 2874d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 288c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki private final AtomicBoolean mBootCompleted = new AtomicBoolean(); 289c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki 290905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki private static final int PACKAGE_MATCH_FLAGS = 291905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki PackageManager.MATCH_DIRECT_BOOT_AWARE 292905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 293905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki | PackageManager.MATCH_UNINSTALLED_PACKAGES; 294905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki 2952e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki // Stats 2962e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki @VisibleForTesting 2972e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki interface Stats { 2982e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki int GET_DEFAULT_HOME = 0; 2992e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki int GET_PACKAGE_INFO = 1; 3002e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki int GET_PACKAGE_INFO_WITH_SIG = 2; 3012e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki int GET_APPLICATION_INFO = 3; 3022e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki int LAUNCHER_PERMISSION_CHECK = 4; 3036c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki int CLEANUP_DANGLING_BITMAPS = 5; 3042e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 3056c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki int COUNT = CLEANUP_DANGLING_BITMAPS + 1; 3062e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 3072e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 3082e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki final Object mStatLock = new Object(); 3092e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 3102e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki @GuardedBy("mStatLock") 3112e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki private final int[] mCountStats = new int[Stats.COUNT]; 3122e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 3132e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki @GuardedBy("mStatLock") 3142e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki private final long[] mDurationStats = new long[Stats.COUNT]; 3152e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 3164d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki private static final int PROCESS_STATE_FOREGROUND_THRESHOLD = 3174d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; 3184d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public ShortcutService(Context context) { 320aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki this(context, BackgroundThread.get().getLooper()); 321aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } 322aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 323aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki @VisibleForTesting 324aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki ShortcutService(Context context, Looper looper) { 3256f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki mContext = Preconditions.checkNotNull(context); 3266f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki LocalServices.addService(ShortcutServiceInternal.class, new LocalService()); 327aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki mHandler = new Handler(looper); 3280acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki mIPackageManager = AppGlobals.getPackageManager(); 3292d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 330cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki mUserManager = context.getSystemService(UserManager.class); 331cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 332cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false); 3334d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3344d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE 3354d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki | ActivityManager.UID_OBSERVER_GONE); 3366f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 3376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 3382e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki void logDurationStat(int statId, long start) { 3392e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki synchronized (mStatLock) { 3402e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki mCountStats[statId]++; 3416c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki mDurationStats[statId] += (injectElapsedRealtime() - start); 3422e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 3432e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 3442e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 3454d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki public long getLocaleChangeSequenceNumber() { 3464d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki return mLocaleChangeSequenceNumber.get(); 3474d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3484d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3494d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki final private IUidObserver mUidObserver = new IUidObserver.Stub() { 3504d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @Override public void onUidStateChanged(int uid, int procState) throws RemoteException { 3514d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki handleOnUidStateChanged(uid, procState); 3524d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3534d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3544d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @Override public void onUidGone(int uid) throws RemoteException { 3554d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki handleOnUidStateChanged(uid, ActivityManager.MAX_PROCESS_STATE); 3564d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3574d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3584d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @Override public void onUidActive(int uid) throws RemoteException { 3594d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3604d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3614d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @Override public void onUidIdle(int uid) throws RemoteException { 3624d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3634d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki }; 3644d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3654d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki void handleOnUidStateChanged(int uid, int procState) { 3664d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki if (DEBUG_PROCSTATE) { 3674d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki Slog.d(TAG, "onUidStateChanged: uid=" + uid + " state=" + procState); 3684d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3694d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki synchronized (mLock) { 3704d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki mUidState.put(uid, procState); 3714d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3724d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // We need to keep track of last time an app comes to foreground. 3734d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // See ShortcutPackage.getApiCallCount() for how it's used. 3744d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // It doesn't have to be persisted, but it needs to be the elapsed time. 3754d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki if (isProcessStateForeground(procState)) { 3764d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki mUidLastForegroundElapsedTime.put(uid, injectElapsedRealtime()); 3774d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3784d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3794d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3804d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3814d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki private boolean isProcessStateForeground(int processState) { 3824d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki return processState <= PROCESS_STATE_FOREGROUND_THRESHOLD; 3834d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3844d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3854d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki boolean isUidForegroundLocked(int uid) { 3864d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki if (uid == Process.SYSTEM_UID) { 3874d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // IUidObserver doesn't report the state of SYSTEM, but it always has bound services, 3884d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // so it's foreground anyway. 3894d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki return true; 3904d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3914d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki return isProcessStateForeground(mUidState.get(uid, ActivityManager.MAX_PROCESS_STATE)); 3924d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3934d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3944d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki long getUidLastForegroundElapsedTimeLocked(int uid) { 3954d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki return mUidLastForegroundElapsedTime.get(uid); 3964d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 3974d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 3986f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 3996f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * System service lifecycle. 4006f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 4016f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public static final class Lifecycle extends SystemService { 4026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final ShortcutService mService; 4036f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public Lifecycle(Context context) { 4056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki super(context); 4066f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki mService = new ShortcutService(context); 4076f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4096f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 4106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public void onStart() { 4116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki publishBinderService(Context.SHORTCUT_SERVICE, mService); 4126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 4156f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public void onBootPhase(int phase) { 4166f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki mService.onBootPhase(phase); 4176f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4186f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 4206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public void onCleanupUser(int userHandle) { 421cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki mService.handleCleanupUser(userHandle); 4226f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4236f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 425f3a572b5c0cab23a435bd90414d25de84e00398eMakoto Onuki public void onUnlockUser(int userId) { 426cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki mService.handleUnlockUser(userId); 4276f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4286f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4296f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4306f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** lifecycle event */ 4316f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki void onBootPhase(int phase) { 4326f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (DEBUG) { 4336f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.d(TAG, "onBootPhase: " + phase); 4346f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4356f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki switch (phase) { 4366f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki case SystemService.PHASE_LOCK_SETTINGS_READY: 4376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki initialize(); 4386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki break; 439c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki case SystemService.PHASE_BOOT_COMPLETED: 440c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki mBootCompleted.set(true); 441c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki break; 4426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** lifecycle event */ 446cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki void handleUnlockUser(int userId) { 447cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki synchronized (mLock) { 448cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki // Preload 449cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki getUserShortcutsLocked(userId); 4500acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 45139686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki checkPackageChanges(userId); 452cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 4536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** lifecycle event */ 456cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki void handleCleanupUser(int userId) { 457cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki synchronized (mLock) { 458cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki unloadUserLocked(userId); 459cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 460cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 461cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 462cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki private void unloadUserLocked(int userId) { 463cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki if (DEBUG) { 464cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki Slog.d(TAG, "unloadUserLocked: user=" + userId); 465cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 466aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki // Save all dirty information. 467aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki saveDirtyInfo(); 468aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 4696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Unload 4703f4b1ca97ad7c31bdbe2ba29264841fb58683e81Makoto Onuki mUsers.delete(userId); 4716f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4726f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** Return the base state file name */ 4746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private AtomicFile getBaseStateFile() { 4756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final File path = new File(injectSystemDataPath(), FILENAME_BASE_STATE); 4766f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki path.mkdirs(); 4776f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return new AtomicFile(path); 4786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 4816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Init the instance. (load the state file, etc) 4826f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 4836f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private void initialize() { 4846f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 4854362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki loadConfigurationLocked(); 4866f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki loadBaseStateLocked(); 4876f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4886f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 4896f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 4904362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 4914362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki * Load the configuration from Settings. 4924362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 4934362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki private void loadConfigurationLocked() { 4944362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki updateConfigurationLocked(injectShortcutManagerConstants()); 4954362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 4964362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 4974362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki /** 4984362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki * Load the configuration from Settings. 4994362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki */ 5004362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 5014362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki boolean updateConfigurationLocked(String config) { 5024362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki boolean result = true; 5034362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5044362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki final KeyValueListParser parser = new KeyValueListParser(','); 5054362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki try { 5064362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki parser.setString(config); 5074362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } catch (IllegalArgumentException e) { 5084362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki // Failed to parse the settings string, log this and move on 5094362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki // with defaults. 5104362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki Slog.e(TAG, "Bad shortcut manager settings", e); 5114362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki result = false; 5124362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 5134362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5145ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki mSaveDelayMillis = Math.max(0, (int) parser.getLong(ConfigConstants.KEY_SAVE_DELAY_MILLIS, 5155ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki DEFAULT_SAVE_DELAY_MS)); 516aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 5175ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki mResetInterval = Math.max(1, parser.getLong( 5184362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC) 5195ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki * 1000L); 5204362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 521b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong( 522b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL)); 5234362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5245ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki mMaxDynamicShortcuts = Math.max(0, (int) parser.getLong( 5255ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP)); 5264362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5275ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki final int iconDimensionDp = Math.max(1, injectIsLowRamDevice() 5284362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki ? (int) parser.getLong( 5294362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM, 5304362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP) 5314362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki : (int) parser.getLong( 5324362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki ConfigConstants.KEY_MAX_ICON_DIMENSION_DP, 5335ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki DEFAULT_MAX_ICON_DIMENSION_DP)); 5344362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5354362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki mMaxIconDimension = injectDipToPixel(iconDimensionDp); 5364362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5374362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki mIconPersistFormat = CompressFormat.valueOf( 5384362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki parser.getString(ConfigConstants.KEY_ICON_FORMAT, DEFAULT_ICON_PERSIST_FORMAT)); 5394362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5404362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki mIconPersistQuality = (int) parser.getLong( 5414362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki ConfigConstants.KEY_ICON_QUALITY, 5424362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki DEFAULT_ICON_PERSIST_QUALITY); 5434362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5444362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki return result; 5454362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 5464362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 5476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 5484362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki String injectShortcutManagerConstants() { 5494362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki return android.provider.Settings.Global.getString( 5504362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki mContext.getContentResolver(), 5514362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki android.provider.Settings.Global.SHORTCUT_MANAGER_CONSTANTS); 5524362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 5535504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 5544362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 5554362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki int injectDipToPixel(int dip) { 5564362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, 5574362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki mContext.getResources().getDisplayMetrics()); 5586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 5596f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 5605504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // === Persisting === 5616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 5626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Nullable 56341066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static String parseStringAttribute(XmlPullParser parser, String attribute) { 5646f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return parser.getAttributeValue(null, attribute); 5656f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 5666f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 5670acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki static boolean parseBooleanAttribute(XmlPullParser parser, String attribute) { 5680acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return parseLongAttribute(parser, attribute) == 1; 5690acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 5700acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 57141066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static int parseIntAttribute(XmlPullParser parser, String attribute) { 57241066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki return (int) parseLongAttribute(parser, attribute); 57341066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki } 57441066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki 575d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki static int parseIntAttribute(XmlPullParser parser, String attribute, int def) { 576d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return (int) parseLongAttribute(parser, attribute, def); 577d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 578d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 57941066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static long parseLongAttribute(XmlPullParser parser, String attribute) { 580d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return parseLongAttribute(parser, attribute, 0); 581d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 582d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 583d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki static long parseLongAttribute(XmlPullParser parser, String attribute, long def) { 5846f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final String value = parseStringAttribute(parser, attribute); 5856f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (TextUtils.isEmpty(value)) { 586d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return def; 5876f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 5886f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki try { 5896f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return Long.parseLong(value); 5906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } catch (NumberFormatException e) { 5916f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.e(TAG, "Error parsing long " + value); 592d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return def; 5936f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 5946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 5956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 5966f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Nullable 59741066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static ComponentName parseComponentNameAttribute(XmlPullParser parser, String attribute) { 5986f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final String value = parseStringAttribute(parser, attribute); 5996f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (TextUtils.isEmpty(value)) { 6006f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return null; 6016f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return ComponentName.unflattenFromString(value); 6036f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Nullable 60641066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static Intent parseIntentAttribute(XmlPullParser parser, String attribute) { 6076f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final String value = parseStringAttribute(parser, attribute); 6086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (TextUtils.isEmpty(value)) { 6096f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return null; 6106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki try { 6126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return Intent.parseUri(value, /* flags =*/ 0); 6136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } catch (URISyntaxException e) { 6146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.e(TAG, "Error parsing intent", e); 6156f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return null; 6166f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6176f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6186f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 61941066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static void writeTagValue(XmlSerializer out, String tag, String value) throws IOException { 6206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (TextUtils.isEmpty(value)) return; 6216f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6226f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.startTag(null, tag); 6236f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.attribute(null, ATTR_VALUE, value); 6246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.endTag(null, tag); 6256f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6266f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 62741066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static void writeTagValue(XmlSerializer out, String tag, long value) throws IOException { 6286f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki writeTagValue(out, tag, Long.toString(value)); 6296f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6306f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6312d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki static void writeTagValue(XmlSerializer out, String tag, ComponentName name) throws IOException { 6322d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (name == null) return; 6332d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki writeTagValue(out, tag, name.flattenToString()); 6342d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 6352d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 63641066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static void writeTagExtra(XmlSerializer out, String tag, PersistableBundle bundle) 6376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki throws IOException, XmlPullParserException { 6386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (bundle == null) return; 6396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.startTag(null, tag); 6416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki bundle.saveToXml(out); 6426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.endTag(null, tag); 6436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 64541066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static void writeAttr(XmlSerializer out, String name, String value) throws IOException { 6466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (TextUtils.isEmpty(value)) return; 6476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.attribute(null, name, value); 6496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 65141066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static void writeAttr(XmlSerializer out, String name, long value) throws IOException { 6526f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki writeAttr(out, name, String.valueOf(value)); 6536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6550acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException { 6560acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki if (value) { 6570acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki writeAttr(out, name, "1"); 6580acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 6590acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 6600acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 66141066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static void writeAttr(XmlSerializer out, String name, ComponentName comp) throws IOException { 6626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (comp == null) return; 6636f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki writeAttr(out, name, comp.flattenToString()); 6646f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6656f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 66641066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static void writeAttr(XmlSerializer out, String name, Intent intent) throws IOException { 6676f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (intent == null) return; 6686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki writeAttr(out, name, intent.toUri(/* flags =*/ 0)); 6706f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6716f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6726f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 6736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki void saveBaseStateLocked() { 6746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final AtomicFile file = getBaseStateFile(); 6756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (DEBUG) { 676aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki Slog.d(TAG, "Saving to " + file.getBaseFile()); 6776f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 6786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki FileOutputStream outs = null; 6806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki try { 6816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki outs = file.startWrite(); 6826f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6836f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Write to XML 6846f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki XmlSerializer out = new FastXmlSerializer(); 6856f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.setOutput(outs, StandardCharsets.UTF_8.name()); 6866f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.startDocument(null, true); 6876f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.startTag(null, TAG_ROOT); 6886f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6896f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Body. 6906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime); 6914d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki writeTagValue(out, TAG_LOCALE_CHANGE_SEQUENCE_NUMBER, 6924d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki mLocaleChangeSequenceNumber.get()); 6936f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Epilogue. 6956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.endTag(null, TAG_ROOT); 6966f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki out.endDocument(); 6976f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 6986f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Close. 6996f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki file.finishWrite(outs); 7006f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } catch (IOException e) { 7016f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e); 7026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki file.failWrite(outs); 7036f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7066f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private void loadBaseStateLocked() { 7076f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki mRawLastResetTime = 0; 7086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7096f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final AtomicFile file = getBaseStateFile(); 7106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (DEBUG) { 711aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki Slog.d(TAG, "Loading from " + file.getBaseFile()); 7126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki try (FileInputStream in = file.openRead()) { 7146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki XmlPullParser parser = Xml.newPullParser(); 7156f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki parser.setInput(in, StandardCharsets.UTF_8.name()); 7166f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7176f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki int type; 7186f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 7196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (type != XmlPullParser.START_TAG) { 7206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki continue; 7216f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7226f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final int depth = parser.getDepth(); 7236f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Check the root tag 7246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final String tag = parser.getName(); 7256f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (depth == 1) { 7266f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (!TAG_ROOT.equals(tag)) { 7276f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.e(TAG, "Invalid root tag: " + tag); 7286f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return; 7296f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7306f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki continue; 7316f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7326f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Assume depth == 2 7336f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki switch (tag) { 7346f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki case TAG_LAST_RESET_TIME: 7356f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki mRawLastResetTime = parseLongAttribute(parser, ATTR_VALUE); 7366f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki break; 7374d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki case TAG_LOCALE_CHANGE_SEQUENCE_NUMBER: 7384d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki mLocaleChangeSequenceNumber.set(parseLongAttribute(parser, ATTR_VALUE)); 7394d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki break; 7406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki default: 7416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.e(TAG, "Invalid tag: " + tag); 7426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki break; 7436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } catch (FileNotFoundException e) { 7466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Use the default 7476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } catch (IOException|XmlPullParserException e) { 7486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e); 7496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki mRawLastResetTime = 0; 7516f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7526f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Adjust the last reset time. 7536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki getLastResetTimeLocked(); 7546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7566f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private void saveUserLocked(@UserIdInt int userId) { 7576f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final File path = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES); 7586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (DEBUG) { 759aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki Slog.d(TAG, "Saving to " + path); 7606f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki path.mkdirs(); 7626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final AtomicFile file = new AtomicFile(path); 7639da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki FileOutputStream os = null; 7646f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki try { 7659da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki os = file.startWrite(); 7666f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7679da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki saveUserInternalLocked(userId, os, /* forBackup= */ false); 7686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7699da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki file.finishWrite(os); 7709da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } catch (XmlPullParserException|IOException e) { 7716f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e); 7729da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki file.failWrite(os); 7736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7769da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os, 7779da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki boolean forBackup) throws IOException, XmlPullParserException { 7789da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 7799da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final BufferedOutputStream bos = new BufferedOutputStream(os); 7809da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 7819da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki // Write to XML 7829da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki XmlSerializer out = new FastXmlSerializer(); 7839da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki out.setOutput(bos, StandardCharsets.UTF_8.name()); 7849da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki out.startDocument(null, true); 7859da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 786c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki getUserShortcutsLocked(userId).saveToXml(out, forBackup); 7879da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 7889da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki out.endDocument(); 7899da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 7909da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki bos.flush(); 7919da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki os.flush(); 7929da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 7939da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 79441066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static IOException throwForInvalidTag(int depth, String tag) throws IOException { 7956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki throw new IOException(String.format("Invalid tag '%s' found at depth %d", tag, depth)); 7966f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 7976f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 7989da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki static void warnForInvalidTag(int depth, String tag) throws IOException { 7999da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth)); 8009da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 8019da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 8026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Nullable 8033145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki private ShortcutUser loadUserLocked(@UserIdInt int userId) { 8046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final File path = new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES); 8056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (DEBUG) { 806aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki Slog.d(TAG, "Loading from " + path); 8076f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 8086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final AtomicFile file = new AtomicFile(path); 8096f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 8106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final FileInputStream in; 8116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki try { 8126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki in = file.openRead(); 8136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } catch (FileNotFoundException e) { 8146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (DEBUG) { 815aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki Slog.d(TAG, "Not found " + path); 8166f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 8176f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return null; 8186f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 8196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki try { 8206c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final ShortcutUser ret = loadUserInternal(userId, in, /* forBackup= */ false); 8216c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki cleanupDanglingBitmapDirectoriesLocked(userId, ret); 8226c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki return ret; 8236f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } catch (IOException|XmlPullParserException e) { 8246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e); 8256f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return null; 8266f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } finally { 8276f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki IoUtils.closeQuietly(in); 8286f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 8296f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 8306f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 8319da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is, 8329da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki boolean fromBackup) throws XmlPullParserException, IOException { 8339da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 8349da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final BufferedInputStream bis = new BufferedInputStream(is); 8359da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 8369da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki ShortcutUser ret = null; 8379da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki XmlPullParser parser = Xml.newPullParser(); 8389da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki parser.setInput(bis, StandardCharsets.UTF_8.name()); 8399da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 8409da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki int type; 8419da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 8429da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (type != XmlPullParser.START_TAG) { 8439da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki continue; 8449da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 8459da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final int depth = parser.getDepth(); 8469da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 8479da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final String tag = parser.getName(); 8489da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (DEBUG_LOAD) { 8499da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.d(TAG, String.format("depth=%d type=%d name=%s", 8509da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki depth, type, tag)); 8519da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 8529da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if ((depth == 1) && ShortcutUser.TAG_ROOT.equals(tag)) { 8539da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki ret = ShortcutUser.loadFromXml(this, parser, userId, fromBackup); 8549da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki continue; 8559da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 8569da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki throwForInvalidTag(depth, tag); 8579da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 8589da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki return ret; 8599da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 8609da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 8616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private void scheduleSaveBaseState() { 8620acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki scheduleSaveInner(UserHandle.USER_NULL); // Special case -- use USER_NULL for base state. 863aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } 864aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 865aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki void scheduleSaveUser(@UserIdInt int userId) { 8660acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki scheduleSaveInner(userId); 867aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } 868aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 869aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki // In order to re-schedule, we need to reuse the same instance, so keep it in final. 870aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki private final Runnable mSaveDirtyInfoRunner = this::saveDirtyInfo; 871aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki 8720acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private void scheduleSaveInner(@UserIdInt int userId) { 873aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki if (DEBUG) { 874aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki Slog.d(TAG, "Scheduling to save for " + userId); 875aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } 8766f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 877aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki if (!mDirtyUserIds.contains(userId)) { 878aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki mDirtyUserIds.add(userId); 879aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } 8806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 881aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki // If already scheduled, remove that and re-schedule in N seconds. 882aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki mHandler.removeCallbacks(mSaveDirtyInfoRunner); 883aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki mHandler.postDelayed(mSaveDirtyInfoRunner, mSaveDelayMillis); 8846f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 8856f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 886aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki @VisibleForTesting 887aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki void saveDirtyInfo() { 888aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki if (DEBUG) { 889aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki Slog.d(TAG, "saveDirtyInfo"); 890aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } 8916f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 892aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) { 893aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki final int userId = mDirtyUserIds.get(i); 894aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki if (userId == UserHandle.USER_NULL) { // USER_NULL for base state. 895aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki saveBaseStateLocked(); 896aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } else { 897aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki saveUserLocked(userId); 898aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } 899aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki } 900aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki mDirtyUserIds.clear(); 9016f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9036f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** Return the last reset time. */ 9056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki long getLastResetTimeLocked() { 906aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki updateTimesLocked(); 9076f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return mRawLastResetTime; 9086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9096f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** Return the next reset time. */ 9116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki long getNextResetTimeLocked() { 912aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki updateTimesLocked(); 9136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return mRawLastResetTime + mResetInterval; 9146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9156f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9164554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki static boolean isClockValid(long time) { 9174554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki return time >= 1420070400; // Thu, 01 Jan 2015 00:00:00 GMT 9184554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki } 9194554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki 9206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 9216f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Update the last reset time. 9226f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 923aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki private void updateTimesLocked() { 9246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9256f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final long now = injectCurrentTimeMillis(); 9266f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9276f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final long prevLastResetTime = mRawLastResetTime; 9286f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9296f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (mRawLastResetTime == 0) { // first launch. 9306f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // TODO Randomize?? 9316f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki mRawLastResetTime = now; 9326f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } else if (now < mRawLastResetTime) { 9336f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Clock rewound. 9344554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki if (isClockValid(now)) { 935aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki Slog.w(TAG, "Clock rewound"); 9364554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki // TODO Randomize?? 9374554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki mRawLastResetTime = now; 9384554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki } 9396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } else { 940aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki if ((mRawLastResetTime + mResetInterval) <= now) { 941aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki final long offset = mRawLastResetTime % mResetInterval; 942aa8b94aa79df94d77d0f7698ce532ac98f197a99Makoto Onuki mRawLastResetTime = ((now / mResetInterval) * mResetInterval) + offset; 9436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (prevLastResetTime != mRawLastResetTime) { 9466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki scheduleSaveBaseState(); 9476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 950cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki @GuardedBy("mLock") 951cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki @NonNull 9522e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki private boolean isUserLoadedLocked(@UserIdInt int userId) { 953cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki return mUsers.get(userId) != null; 954cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 955cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 9566f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** Return the per-user state. */ 9576f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @GuardedBy("mLock") 9586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @NonNull 9593145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki ShortcutUser getUserShortcutsLocked(@UserIdInt int userId) { 9603145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki ShortcutUser userPackages = mUsers.get(userId); 9616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (userPackages == null) { 9626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki userPackages = loadUserLocked(userId); 9636f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (userPackages == null) { 964c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki userPackages = new ShortcutUser(this, userId); 9656f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9663f4b1ca97ad7c31bdbe2ba29264841fb58683e81Makoto Onuki mUsers.put(userId, userPackages); 9676f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return userPackages; 9696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9706f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9712e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) { 9722e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki for (int i = mUsers.size() - 1; i >= 0; i--) { 9732e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki c.accept(mUsers.valueAt(i)); 9742e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 9752e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 9762e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 9776f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** Return the per-user per-package state. */ 9786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @GuardedBy("mLock") 9796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @NonNull 9803145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki ShortcutPackage getPackageShortcutsLocked( 9816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @NonNull String packageName, @UserIdInt int userId) { 982c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki return getUserShortcutsLocked(userId).getPackageShortcuts(packageName); 983de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki } 984de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki 985de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki @GuardedBy("mLock") 986de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki @NonNull 9872e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki ShortcutLauncher getLauncherShortcutsLocked( 9882e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki @NonNull String packageName, @UserIdInt int ownerUserId, 9892e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki @UserIdInt int launcherUserId) { 9902e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki return getUserShortcutsLocked(ownerUserId) 991c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .getLauncherShortcuts(packageName, launcherUserId); 9926f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 9936f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // === Caller validation === 9956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 9965504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki void removeIcon(@UserIdInt int userId, ShortcutInfo shortcut) { 9975504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (shortcut.getBitmapPath() != null) { 9985504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (DEBUG) { 9995504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki Slog.d(TAG, "Removing " + shortcut.getBitmapPath()); 10005504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 10015504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki new File(shortcut.getBitmapPath()).delete(); 10025504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 10035504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.setBitmapPath(null); 10045504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.setIconResourceId(0); 10055504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES); 10065504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 10075504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 10085504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 10090033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) { 10100033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki final File packagePath = new File(getUserBitmapFilePath(userId), packageName); 10110033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki if (!packagePath.isDirectory()) { 10120033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki return; 10130033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki } 10140033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki if (!(FileUtils.deleteContents(packagePath) && packagePath.delete())) { 10150033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki Slog.w(TAG, "Unable to remove directory " + packagePath); 10160033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki } 10170033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki } 10180033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki 10196c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki private void cleanupDanglingBitmapDirectoriesLocked( 10206c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki @UserIdInt int userId, @NonNull ShortcutUser user) { 10216c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (DEBUG) { 10226c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId); 10236c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10246c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final long start = injectElapsedRealtime(); 10256c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki 10266c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final File bitmapDir = getUserBitmapFilePath(userId); 10276c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final File[] children = bitmapDir.listFiles(); 10286c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (children == null) { 10296c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki return; 10306c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10316c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki for (File child : children) { 10326c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (!child.isDirectory()) { 10336c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki continue; 10346c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10356c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final String packageName = child.getName(); 10366c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (DEBUG) { 10376c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki Slog.d(TAG, "cleanupDanglingBitmaps: Found directory=" + packageName); 10386c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10396c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (!user.hasPackage(packageName)) { 10406c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (DEBUG) { 10416c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki Slog.d(TAG, "Removing dangling bitmap directory: " + packageName); 10426c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10436c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki cleanupBitmapsForPackage(userId, packageName); 10446c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } else { 10456c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki cleanupDanglingBitmapFilesLocked(userId, user, packageName, child); 10466c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10476c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10486c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki logDurationStat(Stats.CLEANUP_DANGLING_BITMAPS, start); 10496c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10506c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki 10516c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki private void cleanupDanglingBitmapFilesLocked(@UserIdInt int userId, @NonNull ShortcutUser user, 10526c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki @NonNull String packageName, @NonNull File path) { 10536c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final ArraySet<String> usedFiles = 1054c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki user.getPackageShortcuts(packageName).getUsedBitmapFiles(); 10556c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki 10566c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki for (File child : path.listFiles()) { 10576c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (!child.isFile()) { 10586c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki continue; 10596c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10606c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final String name = child.getName(); 10616c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (!usedFiles.contains(name)) { 10626c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki if (DEBUG) { 10636c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki Slog.d(TAG, "Removing dangling bitmap file: " + child.getAbsolutePath()); 10646c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10656c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki child.delete(); 10666c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10676c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10686c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki } 10696c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki 10705504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki @VisibleForTesting 10715504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki static class FileOutputStreamWithPath extends FileOutputStream { 10725504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki private final File mFile; 10735504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 10745504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki public FileOutputStreamWithPath(File file) throws FileNotFoundException { 10755504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki super(file); 10765504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki mFile = file; 10775504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 10785504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 10795504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki public File getFile() { 10805504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return mFile; 10815504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 10825504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 10835504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 10845504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki /** 10855504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki * Build the cached bitmap filename for a shortcut icon. 10865504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki * 10875504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki * The filename will be based on the ID, except certain characters will be escaped. 10885504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki */ 10895504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki @VisibleForTesting 10905504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki FileOutputStreamWithPath openIconFileForWrite(@UserIdInt int userId, ShortcutInfo shortcut) 10915504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki throws IOException { 10925504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final File packagePath = new File(getUserBitmapFilePath(userId), 10935504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.getPackageName()); 10945504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (!packagePath.isDirectory()) { 10955504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki packagePath.mkdirs(); 10965504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (!packagePath.isDirectory()) { 10975504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki throw new IOException("Unable to create directory " + packagePath); 10985504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 10995504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki SELinux.restorecon(packagePath); 11005504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11015504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 11025504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final String baseName = String.valueOf(injectCurrentTimeMillis()); 11035504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki for (int suffix = 0;; suffix++) { 11045504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final String filename = (suffix == 0 ? baseName : baseName + "_" + suffix) + ".png"; 11055504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final File file = new File(packagePath, filename); 11065504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (!file.exists()) { 11075504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (DEBUG) { 11085504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki Slog.d(TAG, "Saving icon to " + file.getAbsolutePath()); 11095504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11105504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return new FileOutputStreamWithPath(file); 11115504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11125504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11135504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11145504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 11155504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki void saveIconAndFixUpShortcut(@UserIdInt int userId, ShortcutInfo shortcut) { 11165504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (shortcut.hasIconFile() || shortcut.hasIconResource()) { 11175504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return; 11185504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11195504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 11204dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki final long token = injectClearCallingIdentity(); 11215504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki try { 11225504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // Clear icon info on the shortcut. 11235504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.setIconResourceId(0); 11245504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.setBitmapPath(null); 11255504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 11265504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final Icon icon = shortcut.getIcon(); 11275504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (icon == null) { 11285504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return; // has no icon 11295504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11305504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 1131abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Bitmap bitmap; 1132abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Bitmap bitmapToRecycle = null; 11335504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki try { 11345504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki switch (icon.getType()) { 11355504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki case Icon.TYPE_RESOURCE: { 11365504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki injectValidateIconResPackage(shortcut, icon); 11375504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 11385504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.setIconResourceId(icon.getResId()); 11395504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES); 11405504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return; 11415504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11425504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki case Icon.TYPE_BITMAP: { 1143abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki bitmap = icon.getBitmap(); // Don't recycle in this case. 11445504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki break; 11455504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11465504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki default: 11475504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // This shouldn't happen because we've already validated the icon, but 11485504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // just in case. 11495504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki throw ShortcutInfo.getInvalidIconException(); 11505504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11515504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (bitmap == null) { 11525504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki Slog.e(TAG, "Null bitmap detected"); 11535504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return; 11545504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11555504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // Shrink and write to the file. 11565504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki File path = null; 11575504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki try { 11585504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final FileOutputStreamWithPath out = openIconFileForWrite(userId, shortcut); 11595504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki try { 11605504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki path = out.getFile(); 11615504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 1162abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Bitmap shrunk = shrinkBitmap(bitmap, mMaxIconDimension); 1163abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki try { 1164abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki shrunk.compress(mIconPersistFormat, mIconPersistQuality, out); 1165abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki } finally { 1166abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki if (bitmap != shrunk) { 1167abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki shrunk.recycle(); 1168abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki } 1169abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki } 11705504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 11715504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.setBitmapPath(out.getFile().getAbsolutePath()); 11725504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE); 11735504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } finally { 11745504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki IoUtils.closeQuietly(out); 11755504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11765504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } catch (IOException|RuntimeException e) { 11775504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // STOPSHIP Change wtf to e 11785504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki Slog.wtf(ShortcutService.TAG, "Unable to write bitmap to file", e); 11795504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (path != null && path.exists()) { 11805504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki path.delete(); 11815504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11825504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11835504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } finally { 1184abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki if (bitmapToRecycle != null) { 1185abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki bitmapToRecycle.recycle(); 11865504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11875504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // Once saved, we won't use the original icon information, so null it out. 11885504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.clearIcon(); 11895504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11905504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } finally { 11914dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki injectRestoreCallingIdentity(token); 11925504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11935504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 11945504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 11955504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // Unfortunately we can't do this check in unit tests because we fake creator package names, 11965504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // so override in unit tests. 11975504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // TODO CTS this case. 11985504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) { 11995504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (!shortcut.getPackageName().equals(icon.getResPackage())) { 12005504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki throw new IllegalArgumentException( 12015504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki "Icon resource must reside in shortcut owner package"); 12025504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 12035504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 12045504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 12055504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki @VisibleForTesting 12065504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki static Bitmap shrinkBitmap(Bitmap in, int maxSize) { 12075504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // Original width/height. 12085504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final int ow = in.getWidth(); 12095504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final int oh = in.getHeight(); 12105504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if ((ow <= maxSize) && (oh <= maxSize)) { 12115504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (DEBUG) { 12125504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki Slog.d(TAG, String.format("Icon size %dx%d, no need to shrink", ow, oh)); 12135504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 12145504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return in; 12155504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 12165504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final int longerDimension = Math.max(ow, oh); 12175504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 12185504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // New width and height. 12195504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final int nw = ow * maxSize / longerDimension; 12205504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final int nh = oh * maxSize / longerDimension; 12215504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (DEBUG) { 12225504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki Slog.d(TAG, String.format("Icon size %dx%d, shrinking to %dx%d", 12235504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki ow, oh, nw, nh)); 12245504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 12255504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 12265504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final Bitmap scaledBitmap = Bitmap.createBitmap(nw, nh, Bitmap.Config.ARGB_8888); 12275504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final Canvas c = new Canvas(scaledBitmap); 12285504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 12295504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final RectF dst = new RectF(0, 0, nw, nh); 12305504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 12315504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki c.drawBitmap(in, /*src=*/ null, dst, /* paint =*/ null); 12325504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 12335504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return scaledBitmap; 12345504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 12355504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 12365504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // === Caller validation === 12375504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 12386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private boolean isCallerSystem() { 12396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final int callingUid = injectBinderCallingUid(); 12406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID); 12416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 12426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 12436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private boolean isCallerShell() { 12446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final int callingUid = injectBinderCallingUid(); 12456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID; 12466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 12476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 12486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private void enforceSystemOrShell() { 12496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Preconditions.checkState(isCallerSystem() || isCallerShell(), 12506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki "Caller must be system or shell"); 12516f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 12526f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 12536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private void enforceShell() { 12546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Preconditions.checkState(isCallerShell(), "Caller must be shell"); 12556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 12566f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 12579da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki private void enforceSystem() { 12589da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Preconditions.checkState(isCallerSystem(), "Caller must be system"); 12599da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 12609da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 12614d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki private void enforceResetThrottlingPermission() { 12624d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki if (isCallerSystem()) { 12634d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki return; 12644d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 12654d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki injectEnforceCallingPermission( 12664d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki android.Manifest.permission.RESET_SHORTCUT_MANAGER_THROTTLING, null); 12674d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 12684d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 12694d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki /** 12704d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * Somehow overriding ServiceContext.enforceCallingPermission() in the unit tests would confuse 12714d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * mockito. So instead we extracted it here and override it in the tests. 12724d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki */ 12734d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @VisibleForTesting 12744d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki void injectEnforceCallingPermission( 12754d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @NonNull String permission, @Nullable String message) { 12764d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki mContext.enforceCallingPermission(permission, message); 12774d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 12784d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 12796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private void verifyCaller(@NonNull String packageName, @UserIdInt int userId) { 12806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Preconditions.checkStringNotEmpty(packageName, "packageName"); 12816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 12826f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (isCallerSystem()) { 12836f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return; // no check 12846f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 12856f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 12866f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final int callingUid = injectBinderCallingUid(); 12876f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 12886f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Otherwise, make sure the arguments are valid. 12896f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (UserHandle.getUserId(callingUid) != userId) { 12906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki throw new SecurityException("Invalid user-ID"); 12916f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 12925504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (injectGetPackageUid(packageName, userId) == injectBinderCallingUid()) { 12936f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return; // Caller is valid. 12946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 12955ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki throw new SecurityException("Calling package name mismatch"); 12966f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 12976f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 12984dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki void postToHandler(Runnable r) { 12994dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki mHandler.post(r); 13004dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki } 13014dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki 13026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 13036f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Throw if {@code numShortcuts} is bigger than {@link #mMaxDynamicShortcuts}. 13046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 13056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki void enforceMaxDynamicShortcuts(int numShortcuts) { 13066f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (numShortcuts > mMaxDynamicShortcuts) { 13076f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki throw new IllegalArgumentException("Max number of dynamic shortcuts exceeded"); 13086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 13096f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 13106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 13116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 13126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * - Sends a notification to LauncherApps 13136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * - Write to file 13146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 131539686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki void packageShortcutsChanged(@NonNull String packageName, @UserIdInt int userId) { 131639686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki if (DEBUG) { 131739686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki Slog.d(TAG, String.format( 131839686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki "Shortcut changes: package=%s, user=%d", packageName, userId)); 131939686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki } 13206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki notifyListeners(packageName, userId); 13216f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki scheduleSaveUser(userId); 13226f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 13236f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 13246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private void notifyListeners(@NonNull String packageName, @UserIdInt int userId) { 132585694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki final long token = injectClearCallingIdentity(); 132685694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki try { 132785694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki if (!mUserManager.isUserRunning(userId)) { 132885694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki return; 132985694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki } 133085694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki } finally { 133185694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki injectRestoreCallingIdentity(token); 1332cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 13334dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki postToHandler(() -> { 13344dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki final ArrayList<ShortcutChangeListener> copy; 13354dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki synchronized (mLock) { 13364dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki copy = new ArrayList<>(mListeners); 13374dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki } 13384dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki // Note onShortcutChanged() needs to be called with the system service permissions. 13394dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki for (int i = copy.size() - 1; i >= 0; i--) { 13404dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki copy.get(i).onShortcutChanged(packageName, userId); 13414dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki } 13424dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki }); 13436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 13446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 13456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 13466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Clean up / validate an incoming shortcut. 13476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * - Make sure all mandatory fields are set. 13486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * - Make sure the intent's extras are persistable, and them to set 13496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * {@link ShortcutInfo#mIntentPersistableExtras}. Also clear its extras. 13506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * - Clear flags. 13515504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki * 13525504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki * TODO Detailed unit tests 13536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 13545504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) { 13556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Preconditions.checkNotNull(shortcut, "Null shortcut detected"); 13566f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (shortcut.getActivityComponent() != null) { 13576f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Preconditions.checkState( 13586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki shortcut.getPackageName().equals( 13596f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki shortcut.getActivityComponent().getPackageName()), 13606f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki "Activity package name mismatch"); 13616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 13626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 13635504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (!forUpdate) { 13645504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki shortcut.enforceMandatoryFields(); 13655504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 13665504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (shortcut.getIcon() != null) { 13675504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki ShortcutInfo.validateIcon(shortcut.getIcon()); 13685504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 13696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 13705504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki validateForXml(shortcut.getId()); 13715504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki validateForXml(shortcut.getTitle()); 13725504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki validatePersistableBundleForXml(shortcut.getIntentPersistableExtras()); 13735504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki validatePersistableBundleForXml(shortcut.getExtras()); 13746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1375de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki shortcut.replaceFlags(0); 13765504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 13775504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 13785504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // KXmlSerializer is strict and doesn't allow certain characters, so we disallow those 13795504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // characters. 13805504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 13815504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki private static void validatePersistableBundleForXml(PersistableBundle b) { 13825504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (b == null || b.size() == 0) { 13835504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return; 13846f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 13855504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki for (String key : b.keySet()) { 13865504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki validateForXml(key); 13875504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final Object value = b.get(key); 13885504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (value == null) { 13895504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki continue; 13905504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } else if (value instanceof String) { 13915504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki validateForXml((String) value); 13925504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } else if (value instanceof String[]) { 13935504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki for (String v : (String[]) value) { 13945504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki validateForXml(v); 13955504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 13965504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } else if (value instanceof PersistableBundle) { 13975504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki validatePersistableBundleForXml((PersistableBundle) value); 13985504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 13995504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14005504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14016f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14025504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki private static void validateForXml(String s) { 14035504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (TextUtils.isEmpty(s)) { 14045504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return; 14055504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14065504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki for (int i = s.length() - 1; i >= 0; i--) { 14075504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (!isAllowedInXml(s.charAt(i))) { 14085504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki throw new IllegalArgumentException("Unsupported character detected in: " + s); 14095504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14105504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14115504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14135504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki private static boolean isAllowedInXml(char c) { 14145504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd); 14156f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 14166f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14176f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // === APIs === 14186f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 14206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public boolean setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, 14216f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @UserIdInt int userId) { 14226f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 14236f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); 14256f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final int size = newShortcuts.size(); 14266f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14276f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 14283145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); 14296f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14306f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Throttling. 1431c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (!ps.tryApiCall()) { 14326f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return false; 14336f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 14346f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki enforceMaxDynamicShortcuts(size); 14356f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14366f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Validate the shortcuts. 14376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki for (int i = 0; i < size; i++) { 14385504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false); 14396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 14406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // First, remove all un-pinned; dynamic shortcuts 1442c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki ps.deleteAllDynamicShortcuts(); 14436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Then, add/update all. We need to make sure to take over "pinned" flag. 14456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki for (int i = 0; i < size; i++) { 14466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final ShortcutInfo newShortcut = newShortcuts.get(i); 1447c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki ps.addDynamicShortcut(newShortcut); 14486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 14496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 145039686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki packageShortcutsChanged(packageName, userId); 14516f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return true; 14526f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 14536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 14556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public boolean updateShortcuts(String packageName, ParceledListSlice shortcutInfoList, 14566f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @UserIdInt int userId) { 14576f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 14586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14596f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); 14605504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final int size = newShortcuts.size(); 14616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 14633145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); 14646f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14655504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki // Throttling. 1466c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (!ps.tryApiCall()) { 14675504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return false; 14686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 14696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14705504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki for (int i = 0; i < size; i++) { 14715504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final ShortcutInfo source = newShortcuts.get(i); 14725504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki fixUpIncomingShortcutInfo(source, /* forUpdate= */ true); 14735504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 14745504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final ShortcutInfo target = ps.findShortcutById(source.getId()); 14755504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (target != null) { 14765504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final boolean replacingIcon = (source.getIcon() != null); 14775504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (replacingIcon) { 14785504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki removeIcon(userId, target); 14795504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14805504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 14815504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki target.copyNonNullFieldsFrom(source); 14825504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 14835504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (replacingIcon) { 14845504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki saveIconAndFixUpShortcut(userId, target); 14855504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14865504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14875504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 14886f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 148939686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki packageShortcutsChanged(packageName, userId); 14906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14916f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return true; 14926f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 14936f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 14946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 1495b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, 14966f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @UserIdInt int userId) { 14976f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 14986f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1499b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList(); 1500b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki final int size = newShortcuts.size(); 1501b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki 15026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 15033145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); 15046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Throttling. 1506c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (!ps.tryApiCall()) { 15076f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return false; 15086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 1509b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki for (int i = 0; i < size; i++) { 1510b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki final ShortcutInfo newShortcut = newShortcuts.get(i); 15116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1512b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki // Validate the shortcut. 1513b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false); 15146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1515b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki // Add it. 1516c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki ps.addDynamicShortcut(newShortcut); 1517b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki } 15186f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 151939686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki packageShortcutsChanged(packageName, userId); 15206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15216f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return true; 15226f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 15236f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 152520c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki public void disableShortcuts(String packageName, List shortcutIds, 152620c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki String disabledMessage, int disabledMessageResId, @UserIdInt int userId) { 152720c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki verifyCaller(packageName, userId); 152820c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided"); 152920c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki 153020c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki synchronized (mLock) { 153120c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki // TODO implement it. 153220c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } 153320c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki packageShortcutsChanged(packageName, userId); 153420c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } 153520c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki 153620c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki @Override 1537b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki public void removeDynamicShortcuts(String packageName, List shortcutIds, 15386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @UserIdInt int userId) { 15396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 1540b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided"); 15416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 1543b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki for (int i = shortcutIds.size() - 1; i >= 0; i--) { 1544c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId( 1545b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki Preconditions.checkStringNotEmpty((String) shortcutIds.get(i))); 1546b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki } 15476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 154839686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki packageShortcutsChanged(packageName, userId); 15496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 15506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15516f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 1552b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) { 15536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 15546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 1556c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts(); 15576f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 155839686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki packageShortcutsChanged(packageName, userId); 15596f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 15606f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 15626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName, 15636f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @UserIdInt int userId) { 15646f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 15656f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 15666f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return getShortcutsWithQueryLocked( 15676f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, 15686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki ShortcutInfo::isDynamic); 15696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 15706f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 15716f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15726f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 15736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName, 15746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @UserIdInt int userId) { 15756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 15766f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 15776f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return getShortcutsWithQueryLocked( 15786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, 15796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki ShortcutInfo::isPinned); 15806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 15816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 15826f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15836f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName, 15846f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) { 15856f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15866f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final ArrayList<ShortcutInfo> ret = new ArrayList<>(); 15876f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1588c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki getPackageShortcutsLocked(packageName, userId).findAll(ret, query, cloneFlags); 15896f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return new ParceledListSlice<>(ret); 15916f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 15926f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15936f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 15946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public int getMaxDynamicShortcutCount(String packageName, @UserIdInt int userId) 15956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki throws RemoteException { 15966f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 15976f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 15986f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return mMaxDynamicShortcuts; 15996f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 16006f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 16016f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 16026f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public int getRemainingCallCount(String packageName, @UserIdInt int userId) { 16036f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 16046f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 16056f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 1606b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki return mMaxUpdatesPerInterval 1607c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki - getPackageShortcutsLocked(packageName, userId).getApiCallCount(); 16086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 16096f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 16106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 16116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 16126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public long getRateLimitResetTime(String packageName, @UserIdInt int userId) { 16136f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki verifyCaller(packageName, userId); 16146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 16156f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 16166f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return getNextResetTimeLocked(); 16176f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 16186f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 16196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 16205504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki @Override 162120c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki public int getIconMaxDimensions(String packageName, int userId) { 16225ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki verifyCaller(packageName, userId); 16235ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 16245504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki synchronized (mLock) { 16255504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return mMaxIconDimension; 16265504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 16275504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 16285504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 162920c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki @Override 163020c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki public void reportShortcutUsed(String packageName, String shortcutId, int userId) { 163120c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki verifyCaller(packageName, userId); 163220c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki 163320c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki // TODO Implement it. 163420c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } 163520c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki 16366f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 16376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Reset all throttling, for developer options and command line. Only system/shell can call it. 16386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 16396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 16406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public void resetThrottling() { 16416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki enforceSystemOrShell(); 16426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 16434554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki resetThrottlingInner(getCallingUserId()); 16446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 16456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 16464554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki void resetThrottlingInner(@UserIdInt int userId) { 16476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 16484554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki getUserShortcutsLocked(userId).resetThrottling(); 16496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 16504554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki scheduleSaveUser(userId); 16515ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "ShortcutManager: throttling counter reset for user " + userId); 16525ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki } 16535ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 16545ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki void resetAllThrottlingInner() { 16555ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki synchronized (mLock) { 16565ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki mRawLastResetTime = injectCurrentTimeMillis(); 16575ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki } 16585ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki scheduleSaveBaseState(); 16595ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "ShortcutManager: throttling counter reset for all users"); 16606f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 16616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 16624d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki void resetPackageThrottling(String packageName, int userId) { 16634d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki synchronized (mLock) { 16644d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki getPackageShortcutsLocked(packageName, userId) 16654d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki .resetRateLimitingForCommandLineNoSaving(); 16664d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki saveUserLocked(userId); 16674d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 16684d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 16694d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 16704d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @Override 16714d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki public void onApplicationActive(String packageName, int userId) { 16724d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki if (DEBUG) { 16734d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki Slog.d(TAG, "onApplicationActive: package=" + packageName + " userid=" + userId); 16744d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 16754d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki enforceResetThrottlingPermission(); 16764d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki resetPackageThrottling(packageName, userId); 16774d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 16784d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 16792d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // We override this method in unit tests to do a simpler check. 16802d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) { 16812d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki return hasShortcutHostPermissionInner(callingPackage, userId); 16822d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 16832d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 16842d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // This method is extracted so we can directly call this method from unit tests, 16852d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // even when hasShortcutPermission() is overridden. 16862d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki @VisibleForTesting 16872d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) { 16882d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki synchronized (mLock) { 16896c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final long start = injectElapsedRealtime(); 16902d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 16913145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki final ShortcutUser user = getUserShortcutsLocked(userId); 16922d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 16932d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki final List<ResolveInfo> allHomeCandidates = new ArrayList<>(); 16942d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 16952d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // Default launcher from package manager. 16966c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final long startGetHomeActivitiesAsUser = injectElapsedRealtime(); 16972d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki final ComponentName defaultLauncher = injectPackageManagerInternal() 16982d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki .getHomeActivitiesAsUser(allHomeCandidates, userId); 16992e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser); 17002d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 17012d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki ComponentName detected; 17022d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (defaultLauncher != null) { 17032d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki detected = defaultLauncher; 17042d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (DEBUG) { 17052d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki Slog.v(TAG, "Default launcher from PM: " + detected); 17062d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17072d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } else { 1708c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki detected = user.getDefaultLauncherComponent(); 17092d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 17102d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // TODO: Make sure it's still enabled. 17112d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (DEBUG) { 17122d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki Slog.v(TAG, "Cached launcher: " + detected); 17132d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17142d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17152d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 17162d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (detected == null) { 17172d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // If we reach here, that means it's the first check since the user was created, 17182d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // and there's already multiple launchers and there's no default set. 17192d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // Find the system one with the highest priority. 17202d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // (We need to check the priority too because of FallbackHome in Settings.) 17212d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // If there's no system launcher yet, then no one can access shortcuts, until 17222d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // the user explicitly 17232d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki final int size = allHomeCandidates.size(); 17242d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 17252d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki int lastPriority = Integer.MIN_VALUE; 17262d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki for (int i = 0; i < size; i++) { 17272d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki final ResolveInfo ri = allHomeCandidates.get(i); 17282d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (!ri.activityInfo.applicationInfo.isSystemApp()) { 17292d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki continue; 17302d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17312d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (DEBUG) { 17322d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki Slog.d(TAG, String.format("hasShortcutPermissionInner: pkg=%s prio=%d", 17332d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki ri.activityInfo.getComponentName(), ri.priority)); 17342d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17352d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (ri.priority < lastPriority) { 17362d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki continue; 17372d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17382d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki detected = ri.activityInfo.getComponentName(); 17392d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki lastPriority = ri.priority; 17402d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17412d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17422e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki logDurationStat(Stats.LAUNCHER_PERMISSION_CHECK, start); 17432e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 17442d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (detected != null) { 17452d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (DEBUG) { 17462d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki Slog.v(TAG, "Detected launcher: " + detected); 17472d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 1748c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki user.setDefaultLauncherComponent(detected); 17492d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki return detected.getPackageName().equals(callingPackage); 17502d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } else { 17512d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // Default launcher not found. 17522d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki return false; 17532d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17542d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17552d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 17562d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 1757cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki // === House keeping === 1758cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 17599ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId) { 17609ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki synchronized (mLock) { 17619ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki forEachLoadedUserLocked(user -> 17629ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki cleanUpPackageLocked(packageName, user.getUserId(), packageUserId)); 17639ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki } 17645ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki } 17655ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 17662e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki /** 17672e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki * Remove all the information associated with a package. This will really remove all the 17682e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki * information, including the restore information (i.e. it'll remove packages even if they're 17692e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki * shadow). 17709ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki * 17719ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki * This is called when an app is uninstalled, or an app gets "clear data"ed. 17722e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki */ 17739ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki @VisibleForTesting 17749ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) { 1775d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki final boolean wasUserLoaded = isUserLoadedLocked(owningUserId); 1776cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 17779ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki final ShortcutUser user = getUserShortcutsLocked(owningUserId); 1778cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki boolean doNotify = false; 1779cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 1780cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki // First, remove the package from the package list (if the package is a publisher). 1781d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki if (packageUserId == owningUserId) { 1782c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (user.removePackage(packageName) != null) { 1783d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki doNotify = true; 1784d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 1785cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 1786d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 1787cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki // Also remove from the launcher list (if the package is a launcher). 17889ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki user.removeLauncher(packageUserId, packageName); 1789cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 1790cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki // Then remove pinned shortcuts from all launchers. 17914d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki user.forAllLaunchers(l -> l.cleanUpPackage(packageName, packageUserId)); 17924d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 17934d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // Now there may be orphan shortcuts because we removed pinned shortcuts at the previous 1794cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki // step. Remove them too. 1795c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki user.forAllPackages(p -> p.refreshPinnedFlags()); 1796cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 1797d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki scheduleSaveUser(owningUserId); 1798cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 1799cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki if (doNotify) { 1800d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki notifyListeners(packageName, owningUserId); 1801cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 1802cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 1803cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki if (!wasUserLoaded) { 1804cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki // Note this will execute the scheduled save. 1805d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki unloadUserLocked(owningUserId); 1806cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 1807cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 1808cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 18096f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 18106f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Entry point from {@link LauncherApps}. 18116f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 18126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private class LocalService extends ShortcutServiceInternal { 18132e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 18146f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 1815d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki public List<ShortcutInfo> getShortcuts(int launcherUserId, 18166f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @NonNull String callingPackage, long changedSince, 1817abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki @Nullable String packageName, @Nullable List<String> shortcutIds, 1818abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki @Nullable ComponentName componentName, 18196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki int queryFlags, int userId) { 18206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final ArrayList<ShortcutInfo> ret = new ArrayList<>(); 182120c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki final boolean cloneKeyFieldOnly = 182220c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0); 182320c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki final int cloneFlag = cloneKeyFieldOnly ? ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO 182420c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki : ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER; 1825abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki if (packageName == null) { 1826abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki shortcutIds = null; // LauncherAppsService already threw for it though. 1827abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki } 18286f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 18296f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 18302e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) 1831c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .attemptToRestoreIfNeededAndSave(); 18322e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 18336f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (packageName != null) { 1834d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki getShortcutsInnerLocked(launcherUserId, 1835abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki callingPackage, packageName, shortcutIds, changedSince, 1836de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki componentName, queryFlags, userId, ret, cloneFlag); 18376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } else { 18384d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki final List<String> shortcutIdsF = shortcutIds; 18394d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki getUserShortcutsLocked(userId).forAllPackages(p -> { 1840d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki getShortcutsInnerLocked(launcherUserId, 18414d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki callingPackage, p.getPackageName(), shortcutIdsF, changedSince, 1842de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki componentName, queryFlags, userId, ret, cloneFlag); 18434d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki }); 18446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 18456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 184620c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki // Resolve all strings if needed. 184720c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki if (!cloneKeyFieldOnly) { 184820c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki final long token = injectClearCallingIdentity(); 184920c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki try { 185020c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki for (int i = ret.size() - 1; i >= 0; i--) { 185120c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki try { 185220c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki ret.get(i).resolveStringsRequiringCrossUser(mContext); 185320c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } catch (NameNotFoundException e) { 185420c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki continue; 185520c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } 185620c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } 185720c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } finally { 185820c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki injectRestoreCallingIdentity(token); 185920c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } 186020c95f854e54b71caa49f0efe07d47d1e6afd435Makoto Onuki } 18616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return ret; 18626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 18636f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 1864d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage, 1865abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince, 18666f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Nullable ComponentName componentName, int queryFlags, 18676f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) { 1868abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki final ArraySet<String> ids = shortcutIds == null ? null 1869abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki : new ArraySet<>(shortcutIds); 1870abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki 1871c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki final ShortcutPackage p = getUserShortcutsLocked(userId) 1872c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .getPackageShortcutsIfExists(packageName); 1873c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (p == null) { 1874c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki return; // No need to instantiate ShortcutPackage. 1875c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki } 1876c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki 1877c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki p.findAll(ret, 18786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki (ShortcutInfo si) -> { 18796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (si.getLastChangedTimestamp() < changedSince) { 18806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return false; 18816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 1882abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki if (ids != null && !ids.contains(si.getId())) { 1883abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki return false; 1884abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki } 188585694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki if (componentName != null) { 188685694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki if (si.getActivityComponent() != null 188785694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki && !si.getActivityComponent().equals(componentName)) { 188885694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki return false; 188985694526039fb0a80ab74b2dc3ab17bacc1a4a59Makoto Onuki } 18906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 18916f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final boolean matchDynamic = 18926f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki ((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0) 1893de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki && si.isDynamic(); 18946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final boolean matchPinned = 18956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki ((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0) 18966f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki && si.isPinned(); 18976f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return matchDynamic || matchPinned; 1898d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki }, cloneFlag, callingPackage, launcherUserId); 18996f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 19006f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 19016f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 1902d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki public boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage, 1903d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki @NonNull String packageName, @NonNull String shortcutId, int userId) { 1904d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki Preconditions.checkStringNotEmpty(packageName, "packageName"); 1905d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki Preconditions.checkStringNotEmpty(shortcutId, "shortcutId"); 1906d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 1907d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki synchronized (mLock) { 19082e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) 1909c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .attemptToRestoreIfNeededAndSave(); 19102e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 1911d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki final ShortcutInfo si = getShortcutInfoLocked( 1912d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki launcherUserId, callingPackage, packageName, shortcutId, userId); 1913d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return si != null && si.isPinned(); 1914d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 1915d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 1916d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 19172e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki private ShortcutInfo getShortcutInfoLocked( 1918d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki int launcherUserId, @NonNull String callingPackage, 1919d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki @NonNull String packageName, @NonNull String shortcutId, int userId) { 1920d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki Preconditions.checkStringNotEmpty(packageName, "packageName"); 1921d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki Preconditions.checkStringNotEmpty(shortcutId, "shortcutId"); 1922d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 1923c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki final ShortcutPackage p = getUserShortcutsLocked(userId) 1924c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .getPackageShortcutsIfExists(packageName); 1925c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (p == null) { 1926c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki return null; 1927c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki } 1928c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki 1929d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki final ArrayList<ShortcutInfo> list = new ArrayList<>(1); 1930c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki p.findAll(list, 1931d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki (ShortcutInfo si) -> shortcutId.equals(si.getId()), 1932d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki /* clone flags=*/ 0, callingPackage, launcherUserId); 1933d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return list.size() == 0 ? null : list.get(0); 1934d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 1935d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 1936d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki @Override 1937d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki public void pinShortcuts(int launcherUserId, 1938d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki @NonNull String callingPackage, @NonNull String packageName, 19396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @NonNull List<String> shortcutIds, int userId) { 19406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Calling permission must be checked by LauncherAppsImpl. 19416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Preconditions.checkStringNotEmpty(packageName, "packageName"); 19426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Preconditions.checkNotNull(shortcutIds, "shortcutIds"); 19436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 19446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 19459da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final ShortcutLauncher launcher = 19462e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki getLauncherShortcutsLocked(callingPackage, userId, launcherUserId); 1947c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki launcher.attemptToRestoreIfNeededAndSave(); 19489da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 1949c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki launcher.pinShortcuts(userId, packageName, shortcutIds); 19506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 195139686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki packageShortcutsChanged(packageName, userId); 19526f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 19536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 19546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 1955d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki public Intent createShortcutIntent(int launcherUserId, 1956d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki @NonNull String callingPackage, 195743204b8357d781f284037fb8b7b7050ed04a2103Makoto Onuki @NonNull String packageName, @NonNull String shortcutId, int userId) { 19586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Calling permission must be checked by LauncherAppsImpl. 195943204b8357d781f284037fb8b7b7050ed04a2103Makoto Onuki Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty"); 196043204b8357d781f284037fb8b7b7050ed04a2103Makoto Onuki Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty"); 19616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 19626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 19632e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) 1964c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .attemptToRestoreIfNeededAndSave(); 19652e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 1966d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki // Make sure the shortcut is actually visible to the launcher. 1967d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki final ShortcutInfo si = getShortcutInfoLocked( 1968d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki launcherUserId, callingPackage, packageName, shortcutId, userId); 1969d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki // "si == null" should suffice here, but check the flags too just to make sure. 1970d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki if (si == null || !(si.isDynamic() || si.isPinned())) { 1971d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return null; 1972d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 1973d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return si.getIntent(); 19746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 19756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 19766f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 19776f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 19786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public void addListener(@NonNull ShortcutChangeListener listener) { 19796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 19806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki mListeners.add(Preconditions.checkNotNull(listener)); 19816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 19826f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 19835504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 19845504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki @Override 1985abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki public int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage, 1986abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki @NonNull String packageName, @NonNull String shortcutId, int userId) { 1987abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Preconditions.checkNotNull(callingPackage, "callingPackage"); 1988abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Preconditions.checkNotNull(packageName, "packageName"); 1989abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Preconditions.checkNotNull(shortcutId, "shortcutId"); 19905504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 19915504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki synchronized (mLock) { 19922e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) 1993c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .attemptToRestoreIfNeededAndSave(); 19942e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 1995c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki final ShortcutPackage p = getUserShortcutsLocked(userId) 1996c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .getPackageShortcutsIfExists(packageName); 1997c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (p == null) { 1998c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki return 0; 1999c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki } 2000c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki 2001c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId); 20025504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return (shortcutInfo != null && shortcutInfo.hasIconResource()) 20035504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki ? shortcutInfo.getIconResourceId() : 0; 20045504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 20055504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 20065504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 20075504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki @Override 2008d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki public ParcelFileDescriptor getShortcutIconFd(int launcherUserId, 2009abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki @NonNull String callingPackage, @NonNull String packageName, 2010abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki @NonNull String shortcutId, int userId) { 2011abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Preconditions.checkNotNull(callingPackage, "callingPackage"); 2012abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Preconditions.checkNotNull(packageName, "packageName"); 2013abe8442951ff88aa01ed882adb54fb1b3472ca3eMakoto Onuki Preconditions.checkNotNull(shortcutId, "shortcutId"); 20145504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 20155504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki synchronized (mLock) { 20162e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) 2017c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .attemptToRestoreIfNeededAndSave(); 2018c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki 2019c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki final ShortcutPackage p = getUserShortcutsLocked(userId) 2020c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki .getPackageShortcutsIfExists(packageName); 2021c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (p == null) { 2022c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki return null; 2023c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki } 20242e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 2025c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId); 20265504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki if (shortcutInfo == null || !shortcutInfo.hasIconFile()) { 20275504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return null; 20285504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 20295504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki try { 203034d1c919fd4f6b9f1adb7d62dd16ba1fa8e91c79Makoto Onuki if (shortcutInfo.getBitmapPath() == null) { 203134d1c919fd4f6b9f1adb7d62dd16ba1fa8e91c79Makoto Onuki Slog.w(TAG, "null bitmap detected in getShortcutIconFd()"); 203234d1c919fd4f6b9f1adb7d62dd16ba1fa8e91c79Makoto Onuki return null; 203334d1c919fd4f6b9f1adb7d62dd16ba1fa8e91c79Makoto Onuki } 20345504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return ParcelFileDescriptor.open( 20355504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki new File(shortcutInfo.getBitmapPath()), 20365504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki ParcelFileDescriptor.MODE_READ_ONLY); 20375504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } catch (FileNotFoundException e) { 20385504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki Slog.e(TAG, "Icon file not found: " + shortcutInfo.getBitmapPath()); 20395504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return null; 20405504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 20415504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 20425504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 20432d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 20442d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki @Override 2045d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki public boolean hasShortcutHostPermission(int launcherUserId, 2046d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki @NonNull String callingPackage) { 2047d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId); 20482d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 20494d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 20504d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki /** 20514d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * Called by AM when the system locale changes *within the AM lock. ABSOLUTELY do not take 20524d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki * any locks in this method. 20534d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki */ 20544d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @Override 20554d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki public void onSystemLocaleChangedNoLock() { 20564d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // DO NOT HOLD ANY LOCKS HERE. 20574d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 20584d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // We want to reset throttling for all packages for all users. But we can't just do so 20594d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // here because: 20604d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // - We can't load/save users that are locked. 20614d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // - Even for loaded users, resetting the counters would require us to hold mLock. 20624d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // 20634d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // So we use a "pull" model instead. In here, we just increment the "locale change 20644d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // sequence number". Each ShortcutUser has the "last known locale change sequence". 20654d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // 20664d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // This allows ShortcutUser's to detect the system locale change, so they can reset 20674d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki // counters. 20684d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 2069c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki // Ignore all callback during system boot. 2070c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (mBootCompleted.get()) { 2071c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki mLocaleChangeSequenceNumber.incrementAndGet(); 2072c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki if (DEBUG) { 2073c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki Slog.d(TAG, "onSystemLocaleChangedNoLock: " + mLocaleChangeSequenceNumber.get()); 2074c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki } 2075c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki postToHandler(() -> scheduleSaveBaseState()); 2076c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki } 20774d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 20786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 20796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 20800acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki /** 20810acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * Package event callbacks. 20820acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki */ 20830acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki @VisibleForTesting 20840acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki final PackageMonitor mPackageMonitor = new PackageMonitor() { 20850acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki @Override 20860acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki public void onPackageAdded(String packageName, int uid) { 20870acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki handlePackageAdded(packageName, getChangingUserId()); 20880acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 20890acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 2090cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki @Override 2091cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki public void onPackageUpdateFinished(String packageName, int uid) { 2092cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki handlePackageUpdateFinished(packageName, getChangingUserId()); 2093cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 2094cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 2095cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki @Override 2096cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki public void onPackageRemoved(String packageName, int uid) { 2097cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki handlePackageRemoved(packageName, getChangingUserId()); 2098cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 20999ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki 21009ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki @Override 21019ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki public void onPackageDataCleared(String packageName, int uid) { 21029ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki handlePackageDataCleared(packageName, getChangingUserId()); 21039ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki } 21040acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki }; 2105cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 21060acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki /** 210739686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki * Called when a user is unlocked. 210839686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki * - Check all known packages still exist, and otherwise perform cleanup. 210939686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki * - If a package still exists, check the version code. If it's been updated, may need to 211039686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki * update timestamps of its shortcuts. 21110acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki */ 2112d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki @VisibleForTesting 211339686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki void checkPackageChanges(@UserIdInt int ownerUserId) { 21140acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki if (DEBUG) { 211539686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki Slog.d(TAG, "checkPackageChanges() ownerUserId=" + ownerUserId); 2116cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 21179da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final ArrayList<PackageWithUser> gonePackages = new ArrayList<>(); 21180acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 2119d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki synchronized (mLock) { 21202e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki final ShortcutUser user = getUserShortcutsLocked(ownerUserId); 21219da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 21229da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki user.forAllPackageItems(spi -> { 21239da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (spi.getPackageInfo().isShadow()) { 21249da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki return; // Don't delete shadow information. 2125d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 212639686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki final int versionCode = getApplicationVersionCode( 212739686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki spi.getPackageName(), spi.getPackageUserId()); 212839686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki if (versionCode >= 0) { 212939686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki // Package still installed, see if it's updated. 213039686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki getUserShortcutsLocked(ownerUserId).handlePackageUpdated( 2131c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki spi.getPackageName(), versionCode); 213239686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki } else { 213339686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki gonePackages.add(PackageWithUser.of(spi)); 2134d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 21359da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki }); 21369da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (gonePackages.size() > 0) { 2137905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki for (int i = gonePackages.size() - 1; i >= 0; i--) { 2138d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki final PackageWithUser pu = gonePackages.get(i); 21392e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId); 2140905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki } 21410acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 21420acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 21430acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 2144cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 21450acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private void handlePackageAdded(String packageName, @UserIdInt int userId) { 2146cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki if (DEBUG) { 21470acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId)); 21480acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 21490acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki synchronized (mLock) { 21502e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki forEachLoadedUserLocked(user -> 21512e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki user.attemptToRestoreIfNeededAndSave(this, packageName, userId)); 2152cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 2153cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 2154cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 21550acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) { 2156905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki if (DEBUG) { 21579da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.d(TAG, String.format("handlePackageUpdateFinished: %s user=%d", 21589da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki packageName, userId)); 21590acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 21600acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki synchronized (mLock) { 21612e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki forEachLoadedUserLocked(user -> 21622e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki user.attemptToRestoreIfNeededAndSave(this, packageName, userId)); 216339686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki 216439686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki final int versionCode = getApplicationVersionCode(packageName, userId); 216539686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki if (versionCode < 0) { 216639686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki return; // shouldn't happen 216739686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki } 2168c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki getUserShortcutsLocked(userId).handlePackageUpdated(packageName, versionCode); 21690acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 21700acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 21710acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 21722e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki private void handlePackageRemoved(String packageName, @UserIdInt int packageUserId) { 2173cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki if (DEBUG) { 21742e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName, 21752e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki packageUserId)); 2176cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 21779ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki cleanUpPackageForAllLoadedUsers(packageName, packageUserId); 21785ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki } 21795ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 21809ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki private void handlePackageDataCleared(String packageName, int packageUserId) { 21819ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki if (DEBUG) { 21829ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki Slog.d(TAG, String.format("handlePackageDataCleared: %s user=%d", packageName, 21839ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki packageUserId)); 2184cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 21859ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki cleanUpPackageForAllLoadedUsers(packageName, packageUserId); 2186cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 2187cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 21889da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki // === PackageManager interaction === 21890acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 2190905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) { 2191905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki return injectPackageInfo(packageName, userId, true); 21920acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 21930acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 2194905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) { 21959da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final long token = injectClearCallingIdentity(); 2196905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki try { 2197905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki return mIPackageManager.getPackageUid(packageName, PACKAGE_MATCH_FLAGS 2198905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki , userId); 2199905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki } catch (RemoteException e) { 2200905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki // Shouldn't happen. 2201905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki Slog.wtf(TAG, "RemoteException", e); 2202905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki return -1; 22039da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } finally { 22049da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki injectRestoreCallingIdentity(token); 2205905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki } 22060acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 22070acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 22080acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki @VisibleForTesting 22090acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId, 22100acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki boolean getSignatures) { 22116c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final long start = injectElapsedRealtime(); 22129da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final long token = injectClearCallingIdentity(); 22130acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki try { 2214905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS 22150acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki | (getSignatures ? PackageManager.GET_SIGNATURES : 0) 22160acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki , userId); 22170acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } catch (RemoteException e) { 22180acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki // Shouldn't happen. 22190acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki Slog.wtf(TAG, "RemoteException", e); 22200acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return null; 22219da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } finally { 22229da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki injectRestoreCallingIdentity(token); 22232e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 22242e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki logDurationStat( 22252e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki (getSignatures ? Stats.GET_PACKAGE_INFO_WITH_SIG : Stats.GET_PACKAGE_INFO), 22262e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki start); 22270acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 22280acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 22290acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 2230905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki @VisibleForTesting 2231905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) { 22326c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki final long start = injectElapsedRealtime(); 22339da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final long token = injectClearCallingIdentity(); 2234905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki try { 2235905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId); 2236905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki } catch (RemoteException e) { 2237905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki // Shouldn't happen. 2238905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki Slog.wtf(TAG, "RemoteException", e); 2239905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki return null; 22409da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } finally { 22419da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki injectRestoreCallingIdentity(token); 22422e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 22432e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki logDurationStat(Stats.GET_APPLICATION_INFO, start); 2244905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki } 2245905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki } 2246905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki 2247905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki private boolean isApplicationFlagSet(String packageName, int userId, int flags) { 2248905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki final ApplicationInfo ai = injectApplicationInfo(packageName, userId); 2249905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki return (ai != null) && ((ai.flags & flags) == flags); 2250905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki } 2251905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki 22522e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki boolean isPackageInstalled(String packageName, int userId) { 22539da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED); 22549da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 22559da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 225639686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki /** 225739686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki * @return the version code of the package, or -1 if the app is not installed. 225839686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki */ 225939686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki int getApplicationVersionCode(String packageName, int userId) { 226039686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki final ApplicationInfo ai = injectApplicationInfo(packageName, userId); 226139686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki if ((ai == null) || ((ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) { 226239686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki return -1; 226339686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki } 226439686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki return ai.versionCode; 226539686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki } 226639686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki 22679da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki // === Backup & restore === 22689da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 22690acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki boolean shouldBackupApp(String packageName, int userId) { 2270905e8855e7df111f835fecde32598479058fe4dfMakoto Onuki return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_ALLOW_BACKUP); 22710acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 2272cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 22732e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki boolean shouldBackupApp(PackageInfo pi) { 22742e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki return (pi.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0; 22752e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 22762e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 22779da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki @Override 22782e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki public byte[] getBackupPayload(@UserIdInt int userId) { 22799da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki enforceSystem(); 22809da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (DEBUG) { 22819da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.d(TAG, "Backing up user " + userId); 22829da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 22839da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki synchronized (mLock) { 22849da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final ShortcutUser user = getUserShortcutsLocked(userId); 22859da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (user == null) { 22869da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.w(TAG, "Can't backup: user not found: id=" + userId); 22879da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki return null; 22889da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 22899da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 2290c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave()); 22919da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 22929da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki // Then save. 22939da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024); 22949da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki try { 22959da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki saveUserInternalLocked(userId, os, /* forBackup */ true); 22969da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } catch (XmlPullParserException|IOException e) { 22979da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki // Shouldn't happen. 22989da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.w(TAG, "Backup failed.", e); 22999da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki return null; 23009da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 23019da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki return os.toByteArray(); 23029da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 23039da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 23049da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 23059da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki @Override 23062e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki public void applyRestore(byte[] payload, @UserIdInt int userId) { 23079da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki enforceSystem(); 23089da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (DEBUG) { 23099da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.d(TAG, "Restoring user " + userId); 23109da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 23119da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final ShortcutUser user; 23129da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final ByteArrayInputStream is = new ByteArrayInputStream(payload); 23139da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki try { 23149da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki user = loadUserInternal(userId, is, /* fromBackup */ true); 23159da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } catch (XmlPullParserException|IOException e) { 23169da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.w(TAG, "Restoration failed.", e); 23179da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki return; 23189da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 23199da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki synchronized (mLock) { 23209da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki mUsers.put(userId, user); 23212e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 23222e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki // Then purge all the save images. 23232e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki final File bitmapPath = getUserBitmapFilePath(userId); 23242e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki final boolean success = FileUtils.deleteContents(bitmapPath); 23252e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki if (!success) { 23262e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki Slog.w(TAG, "Failed to delete " + bitmapPath); 23272e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 23282e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 23292e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki saveUserLocked(userId); 23309da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 2331cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki } 2332cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 23336f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // === Dump === 23346f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 23356f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 23366f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 23376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 23386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki != PackageManager.PERMISSION_GRANTED) { 23396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println("Permission Denial: can't dump UserManager from from pid=" 23406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki + Binder.getCallingPid() 23416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki + ", uid=" + Binder.getCallingUid() 23426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki + " without permission " 23436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki + android.Manifest.permission.DUMP); 23446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return; 23456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 23464d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki dumpInner(pw, args); 23476f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 23486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 23496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 23504d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki void dumpInner(PrintWriter pw, String[] args) { 23516f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki synchronized (mLock) { 23526f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final long now = injectCurrentTimeMillis(); 23536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print("Now: ["); 23546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(now); 23556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print("] "); 23566f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(formatTime(now)); 23575504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 23586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(" Raw last reset: ["); 23596f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(mRawLastResetTime); 23606f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print("] "); 23616f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(formatTime(mRawLastResetTime)); 23626f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 23636f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final long last = getLastResetTimeLocked(); 23646f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(" Last reset: ["); 23656f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(last); 23666f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print("] "); 23676f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(formatTime(last)); 23686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 23695504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki final long next = getNextResetTimeLocked(); 23706f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(" Next reset: ["); 23716f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(next); 23726f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print("] "); 23736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.print(formatTime(next)); 23744d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 23754d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(" Locale change seq#: "); 23764d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(mLocaleChangeSequenceNumber.get()); 23776f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println(); 23786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 23795ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.print(" Config:"); 23805ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.print(" Max icon dim: "); 23815ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(mMaxIconDimension); 23825ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.print(" Icon format: "); 23835ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(mIconPersistFormat); 23845ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.print(" Icon quality: "); 23852e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki pw.println(mIconPersistQuality); 23860033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki pw.print(" saveDelayMillis: "); 23875ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(mSaveDelayMillis); 23880033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki pw.print(" resetInterval: "); 23895ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(mResetInterval); 23900033b2a190feeda8b41dd62b489aca3a19a09d5bMakoto Onuki pw.print(" maxUpdatesPerInterval: "); 2391b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki pw.println(mMaxUpdatesPerInterval); 239239686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki pw.print(" maxDynamicShortcuts: "); 23935ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(mMaxDynamicShortcuts); 23945504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki pw.println(); 23955504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 23962e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki pw.println(" Stats:"); 23972e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki synchronized (mStatLock) { 23985ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki final String p = " "; 23992e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()"); 24002e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check"); 24012e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 24022e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()"); 24032e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)"); 24042e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo"); 24056c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki 24066c1dbd577bcf2b8bccb9a0d04d741ff7337898f2Makoto Onuki dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps"); 24072e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 24086f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 24093f4b1ca97ad7c31bdbe2ba29264841fb58683e81Makoto Onuki for (int i = 0; i < mUsers.size(); i++) { 24103f4b1ca97ad7c31bdbe2ba29264841fb58683e81Makoto Onuki pw.println(); 2411c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki mUsers.valueAt(i).dump(pw, " "); 24126f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 24134d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 24144d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.println(); 24154d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.println(" UID state:"); 24164d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 24174d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki for (int i = 0; i < mUidState.size(); i++) { 24184d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki final int uid = mUidState.keyAt(i); 24194d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki final int state = mUidState.valueAt(i); 24204d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(" UID="); 24214d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(uid); 24224d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(" state="); 24234d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(state); 24244d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki if (isProcessStateForeground(state)) { 24254d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(" [FG]"); 24264d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 24274d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(" last FG="); 24284d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.print(mUidLastForegroundElapsedTime.get(uid)); 24294d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki pw.println(); 24304d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 24316f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 24326f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 24336f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 243441066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki static String formatTime(long time) { 24356f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki Time tobj = new Time(); 24366f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki tobj.set(time); 24376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return tobj.format("%Y-%m-%d %H:%M:%S"); 24386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 24396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 24402e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) { 24412e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki pw.print(prefix); 24422e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki final int count = mCountStats[statId]; 24432e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki final long dur = mDurationStats[statId]; 24442e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms", 24452e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki label, count, dur, 24462e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki (count == 0 ? 0 : ((double) dur) / count))); 24472e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 24482e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 24496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // === Shell support === 24506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 24516f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 24526f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 24536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki String[] args, ResultReceiver resultReceiver) throws RemoteException { 24546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 24556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki enforceShell(); 24566f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 24576f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver); 24586f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 24596f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 24602d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki static class CommandException extends Exception { 24612d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki public CommandException(String message) { 24622d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki super(message); 24632d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 24642d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 24652d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 24666f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki /** 24676f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki * Handle "adb shell cmd". 24686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki */ 24696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki private class MyShellCommand extends ShellCommand { 24702d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 24712d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private int mUserId = UserHandle.USER_SYSTEM; 24722d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 24732d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void parseOptions(boolean takeUser) 24742d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki throws CommandException { 24752d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki String opt; 24762d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki while ((opt = getNextOption()) != null) { 24772d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki switch (opt) { 24782d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki case "--user": 24792d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki if (takeUser) { 24802d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki mUserId = UserHandle.parseUserArg(getNextArgRequired()); 24812d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki break; 24822d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 24832d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // fallthrough 24842d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki default: 24852d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki throw new CommandException("Unknown option: " + opt); 24862d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 24872d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 24882d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 24892d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 24906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 24916f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public int onCommand(String cmd) { 24926f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki if (cmd == null) { 24936f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return handleDefaultCommands(cmd); 24946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 24956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final PrintWriter pw = getOutPrintWriter(); 24962d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki try { 24972d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki switch (cmd) { 24982d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki case "reset-package-throttling": 24992d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki handleResetPackageThrottling(); 25002d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki break; 25012d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki case "reset-throttling": 25022d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki handleResetThrottling(); 25032d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki break; 25045ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki case "reset-all-throttling": 25055ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki handleResetAllThrottling(); 25065ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki break; 25072d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki case "override-config": 25082d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki handleOverrideConfig(); 25092d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki break; 25102d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki case "reset-config": 25112d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki handleResetConfig(); 25122d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki break; 25132d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki case "clear-default-launcher": 25142d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki handleClearDefaultLauncher(); 25152d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki break; 25162d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki case "get-default-launcher": 25172d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki handleGetDefaultLauncher(); 25182d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki break; 25192d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki case "refresh-default-launcher": 25202d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki handleRefreshDefaultLauncher(); 25212d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki break; 2522ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki case "unload-user": 2523ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki handleUnloadUser(); 2524ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki break; 25255ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki case "clear-shortcuts": 25265ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki handleClearShortcuts(); 25275ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki break; 25282d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki default: 25292d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki return handleDefaultCommands(cmd); 25302d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 25312d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } catch (CommandException e) { 25322d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println("Error: " + e.getMessage()); 25332d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki return 1; 25344362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 25352d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println("Success"); 25362d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki return 0; 25376f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 25386f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 25396f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @Override 25406f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki public void onHelp() { 25416f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final PrintWriter pw = getOutPrintWriter(); 25426f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println("Usage: cmd shortcut COMMAND [options ...]"); 25436f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println(); 25446f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println("cmd shortcut reset-package-throttling [--user USER_ID] PACKAGE"); 25456f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println(" Reset throttling for a package"); 25466f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println(); 25475ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println("cmd shortcut reset-throttling [--user USER_ID]"); 25486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println(" Reset throttling for all packages and users"); 25496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki pw.println(); 25505ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println("cmd shortcut reset-all-throttling"); 25515ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(" Reset the throttling state for all users"); 25525ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(); 25534362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki pw.println("cmd shortcut override-config CONFIG"); 25544362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki pw.println(" Override the configuration for testing (will last until reboot)"); 25554362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki pw.println(); 25564362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki pw.println("cmd shortcut reset-config"); 25574362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki pw.println(" Reset the configuration set with \"update-config\""); 25584362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki pw.println(); 25592d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println("cmd shortcut clear-default-launcher [--user USER_ID]"); 25602d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println(" Clear the cached default launcher"); 25612d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println(); 25622d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println("cmd shortcut get-default-launcher [--user USER_ID]"); 25632d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println(" Show the cached default launcher"); 25642d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println(); 25652d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println("cmd shortcut refresh-default-launcher [--user USER_ID]"); 25662d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println(" Refresh the cached default launcher"); 25672d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki pw.println(); 2568ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki pw.println("cmd shortcut unload-user [--user USER_ID]"); 2569ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki pw.println(" Unload a user from the memory"); 2570ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki pw.println(" (This should not affect any observable behavior)"); 2571ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki pw.println(); 25725ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println("cmd shortcut clear-shortcuts [--user USER_ID] PACKAGE"); 25735ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(" Remove all shortcuts from a package, including pinned shortcuts"); 25745ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki pw.println(); 25756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 25766f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 25775ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki private void handleResetThrottling() throws CommandException { 25784554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki parseOptions(/* takeUser =*/ true); 25794554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki 25805ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "cmd: handleResetThrottling"); 25815ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 25824554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki resetThrottlingInner(mUserId); 25835ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki } 25845ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 25855ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki private void handleResetAllThrottling() { 25865ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "cmd: handleResetAllThrottling"); 25875ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 25885ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki resetAllThrottlingInner(); 25896f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 25906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 25912d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void handleResetPackageThrottling() throws CommandException { 25922d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki parseOptions(/* takeUser =*/ true); 25936f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 25946f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki final String packageName = getNextArgRequired(); 25956f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 25965ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "cmd: handleResetPackageThrottling: " + packageName); 25975ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 25984d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki resetPackageThrottling(packageName, mUserId); 25996f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 26004362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 26012d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void handleOverrideConfig() throws CommandException { 26024362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki final String config = getNextArgRequired(); 26034362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 26045ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "cmd: handleOverrideConfig: " + config); 26055ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 26064362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki synchronized (mLock) { 26074362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki if (!updateConfigurationLocked(config)) { 26082d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki throw new CommandException("override-config failed. See logcat for details."); 26094362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 26104362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 26114362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 26124362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 26132d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void handleResetConfig() { 26145ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "cmd: handleResetConfig"); 26155ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 26164362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki synchronized (mLock) { 26174362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki loadConfigurationLocked(); 26184362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 26192d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 26202d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26212d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void clearLauncher() { 26222d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki synchronized (mLock) { 2623c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki getUserShortcutsLocked(mUserId).setDefaultLauncherComponent(null); 26242d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 26252d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 26262d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26272d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void showLauncher() { 26282d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki synchronized (mLock) { 26292d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki // This ensures to set the cached launcher. Package name doesn't matter. 26302d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki hasShortcutHostPermissionInner("-", mUserId); 26312d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26322d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki getOutPrintWriter().println("Launcher: " 2633c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki + getUserShortcutsLocked(mUserId).getDefaultLauncherComponent()); 26342d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 26352d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 26362d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26372d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void handleClearDefaultLauncher() throws CommandException { 26382d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki parseOptions(/* takeUser =*/ true); 26392d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26402d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki clearLauncher(); 26412d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 26422d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26432d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void handleGetDefaultLauncher() throws CommandException { 26442d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki parseOptions(/* takeUser =*/ true); 26452d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26462d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki showLauncher(); 26472d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 26482d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26492d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki private void handleRefreshDefaultLauncher() throws CommandException { 26502d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki parseOptions(/* takeUser =*/ true); 26512d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 26522d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki clearLauncher(); 26532d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki showLauncher(); 26544362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 2655ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki 2656ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki private void handleUnloadUser() throws CommandException { 2657ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki parseOptions(/* takeUser =*/ true); 2658ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki 26595ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "cmd: handleUnloadUser: " + mUserId); 26605ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 2661ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki ShortcutService.this.handleCleanupUser(mUserId); 2662ac21497f174504472e92b99500709518b8ab2d71Makoto Onuki } 26635ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 26645ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki private void handleClearShortcuts() throws CommandException { 26655ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki parseOptions(/* takeUser =*/ true); 26665ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki final String packageName = getNextArgRequired(); 26675ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 26685ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName); 26695ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki 26709ac59d0438833eee817e4b4e5c03ce5ec8fcf4dcMakoto Onuki ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId); 26715ba0d3e3a3035b67d2ce3a59975145b1e0061ef4Makoto Onuki } 26726f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 26736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 26746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // === Unit test support === 26756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 26766f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Injection point. 26773145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki @VisibleForTesting 26786f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki long injectCurrentTimeMillis() { 26796f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return System.currentTimeMillis(); 26806f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 26816f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 26824d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @VisibleForTesting 26834d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki long injectElapsedRealtime() { 26844d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki return SystemClock.elapsedRealtime(); 26854d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 26864d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 26876f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki // Injection point. 26883145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki @VisibleForTesting 26896f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki int injectBinderCallingUid() { 26906f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return getCallingUid(); 26916f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 26926f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 26933145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki private int getCallingUserId() { 26944554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki return UserHandle.getUserId(injectBinderCallingUid()); 26954554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki } 26964554d0e5b69433ddaa698e976ee584f7f4f14948Makoto Onuki 26974dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki // Injection point. 26983145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki @VisibleForTesting 26994dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki long injectClearCallingIdentity() { 27004dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki return Binder.clearCallingIdentity(); 27014dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki } 27024dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki 27034dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki // Injection point. 27043145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki @VisibleForTesting 27054dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki void injectRestoreCallingIdentity(long token) { 27064dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki Binder.restoreCallingIdentity(token); 27074dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki } 27084dbe0ded4ae9faaef580be80184fca0749e27198Makoto Onuki 2709de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki final void wtf(String message) { 27102e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki wtf( message, /* exception= */ null); 2711de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki } 2712de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki 27132e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki // Injection point. 2714de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki void wtf(String message, Exception e) { 2715de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki Slog.wtf(TAG, message, e); 2716de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki } 2717de66737ae9c5d5c94155820fad65224a83d04c3dMakoto Onuki 27183145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki @VisibleForTesting 27196f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki File injectSystemDataPath() { 27206f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki return Environment.getDataSystemDirectory(); 27216f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 27226f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 27233145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki @VisibleForTesting 27246f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki File injectUserDataPath(@UserIdInt int userId) { 27255504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return new File(Environment.getDataSystemCeDirectory(userId), DIRECTORY_PER_USER); 27265504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 27275504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 27284362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 27295504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki boolean injectIsLowRamDevice() { 27305504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return ActivityManager.isLowRamDeviceStatic(); 27315504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 27325504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 27333145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki @VisibleForTesting 27344d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki void injectRegisterUidObserver(IUidObserver observer, int which) { 27354d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki try { 27364d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki ActivityManagerNative.getDefault().registerUidObserver(observer, which); 27374d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } catch (RemoteException shouldntHappen) { 27384d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 27394d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki } 27404d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki 27414d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki @VisibleForTesting 27422d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki PackageManagerInternal injectPackageManagerInternal() { 27432d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki return mPackageManagerInternal; 27442d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki } 27452d5b465fa9235e66ec176f6d6ffaaa0c18143e41Makoto Onuki 27465504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki File getUserBitmapFilePath(@UserIdInt int userId) { 27475504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS); 27486f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 27496f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 27506f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 27513145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki SparseArray<ShortcutUser> getShortcutsForTest() { 27523f4b1ca97ad7c31bdbe2ba29264841fb58683e81Makoto Onuki return mUsers; 27536f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 27546f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 27556f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 27564362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki int getMaxDynamicShortcutsForTest() { 27574362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki return mMaxDynamicShortcuts; 27584362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 27594362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 27604362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 2761b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki int getMaxUpdatesPerIntervalForTest() { 2762b6d3523dfb5d73ddda4b750a82c059cdc42acf8eMakoto Onuki return mMaxUpdatesPerInterval; 27634362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki } 27644362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki 27654362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki @VisibleForTesting 27664362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki long getResetIntervalForTest() { 27674362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki return mResetInterval; 27686f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 27696f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 27706f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 27714362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki int getMaxIconDimensionForTest() { 27724362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki return mMaxIconDimension; 27736f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 27746f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki 27756f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki @VisibleForTesting 27764362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki CompressFormat getIconPersistFormatForTest() { 27774362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki return mIconPersistFormat; 27785504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki } 27795504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki 27805504622fb01ab9774b5e73d05f86ee03a8b68ab7Makoto Onuki @VisibleForTesting 27814362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki int getIconPersistQualityForTest() { 27824362a66dba0b4cfa9fadb6c8af10c590e4ba880dMakoto Onuki return mIconPersistQuality; 27836f7362d92573e4ae693bc513dca586d6a4eb087bMakoto Onuki } 278441066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki 278541066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki @VisibleForTesting 278641066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) { 278741066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki synchronized (mLock) { 27883145924596ad0db9e8f1f5aead90fb50127243cbMakoto Onuki final ShortcutUser user = mUsers.get(userId); 2789cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki if (user == null) return null; 2790cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 27914d36b3a8c5ba1289d851ef337e46709bba333100Makoto Onuki final ShortcutPackage pkg = user.getAllPackagesForTest().get(packageName); 2792cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki if (pkg == null) return null; 2793cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki 2794cdc78f7137b8036dd96c92ff15fc04ee8fc49c5cMakoto Onuki return pkg.findShortcutById(shortcutId); 279541066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki } 279641066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki } 279741066a61b912f22dd0342a002b4b5e060719cec9Makoto Onuki} 2798