ShortcutUser.java revision 0033b2a190feeda8b41dd62b489aca3a19a09d5b
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.server.pm; 17 18import android.annotation.NonNull; 19import android.annotation.UserIdInt; 20import android.content.ComponentName; 21import android.text.format.Formatter; 22import android.util.ArrayMap; 23import android.util.Slog; 24 25import com.android.internal.util.Preconditions; 26 27import libcore.util.Objects; 28 29import org.xmlpull.v1.XmlPullParser; 30import org.xmlpull.v1.XmlPullParserException; 31import org.xmlpull.v1.XmlSerializer; 32 33import java.io.File; 34import java.io.IOException; 35import java.io.PrintWriter; 36import java.util.function.Consumer; 37 38/** 39 * User information used by {@link ShortcutService}. 40 */ 41class ShortcutUser { 42 private static final String TAG = ShortcutService.TAG; 43 44 static final String TAG_ROOT = "user"; 45 private static final String TAG_LAUNCHER = "launcher"; 46 47 private static final String ATTR_VALUE = "value"; 48 49 static final class PackageWithUser { 50 final int userId; 51 final String packageName; 52 53 private PackageWithUser(int userId, String packageName) { 54 this.userId = userId; 55 this.packageName = Preconditions.checkNotNull(packageName); 56 } 57 58 public static PackageWithUser of(int userId, String packageName) { 59 return new PackageWithUser(userId, packageName); 60 } 61 62 public static PackageWithUser of(ShortcutPackageItem spi) { 63 return new PackageWithUser(spi.getPackageUserId(), spi.getPackageName()); 64 } 65 66 @Override 67 public int hashCode() { 68 return packageName.hashCode() ^ userId; 69 } 70 71 @Override 72 public boolean equals(Object obj) { 73 if (!(obj instanceof PackageWithUser)) { 74 return false; 75 } 76 final PackageWithUser that = (PackageWithUser) obj; 77 78 return userId == that.userId && packageName.equals(that.packageName); 79 } 80 81 @Override 82 public String toString() { 83 return String.format("{Package: %d, %s}", userId, packageName); 84 } 85 } 86 87 @UserIdInt 88 private final int mUserId; 89 90 private final ArrayMap<String, ShortcutPackage> mPackages = new ArrayMap<>(); 91 92 private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>(); 93 94 private ComponentName mLauncherComponent; 95 96 public ShortcutUser(int userId) { 97 mUserId = userId; 98 } 99 100 public int getUserId() { 101 return mUserId; 102 } 103 104 public ArrayMap<String, ShortcutPackage> getAllPackages() { 105 return mPackages; 106 } 107 108 public ShortcutPackage removePackage(@NonNull ShortcutService s, @NonNull String packageName) { 109 final ShortcutPackage removed = mPackages.remove(packageName); 110 111 s.cleanupBitmapsForPackage(mUserId, packageName); 112 113 return removed; 114 } 115 116 public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() { 117 return mLaunchers; 118 } 119 120 public void addLauncher(ShortcutLauncher launcher) { 121 mLaunchers.put(PackageWithUser.of(launcher.getPackageUserId(), 122 launcher.getPackageName()), launcher); 123 } 124 125 public ShortcutLauncher removeLauncher( 126 @UserIdInt int packageUserId, @NonNull String packageName) { 127 return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName)); 128 } 129 130 public ShortcutPackage getPackageShortcuts(ShortcutService s, @NonNull String packageName) { 131 ShortcutPackage ret = mPackages.get(packageName); 132 if (ret == null) { 133 ret = new ShortcutPackage(mUserId, packageName); 134 mPackages.put(packageName, ret); 135 } else { 136 ret.attemptToRestoreIfNeededAndSave(s); 137 } 138 return ret; 139 } 140 141 public ShortcutLauncher getLauncherShortcuts(ShortcutService s, @NonNull String packageName, 142 @UserIdInt int launcherUserId) { 143 final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName); 144 ShortcutLauncher ret = mLaunchers.get(key); 145 if (ret == null) { 146 ret = new ShortcutLauncher(mUserId, packageName, launcherUserId); 147 mLaunchers.put(key, ret); 148 } else { 149 ret.attemptToRestoreIfNeededAndSave(s); 150 } 151 return ret; 152 } 153 154 public void forAllPackageItems(Consumer<ShortcutPackageItem> callback) { 155 { 156 final int size = mLaunchers.size(); 157 for (int i = 0; i < size; i++) { 158 callback.accept(mLaunchers.valueAt(i)); 159 } 160 } 161 { 162 final int size = mPackages.size(); 163 for (int i = 0; i < size; i++) { 164 callback.accept(mPackages.valueAt(i)); 165 } 166 } 167 } 168 169 public void forPackageItem(@NonNull String packageName, @UserIdInt int packageUserId, 170 Consumer<ShortcutPackageItem> callback) { 171 forAllPackageItems(spi -> { 172 if ((spi.getPackageUserId() == packageUserId) 173 && spi.getPackageName().equals(packageName)) { 174 callback.accept(spi); 175 } 176 }); 177 } 178 179 public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName, 180 @UserIdInt int packageUserId) { 181 forPackageItem(packageName, packageUserId, spi -> { 182 spi.attemptToRestoreIfNeededAndSave(s); 183 }); 184 } 185 186 public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup) 187 throws IOException, XmlPullParserException { 188 out.startTag(null, TAG_ROOT); 189 190 ShortcutService.writeTagValue(out, TAG_LAUNCHER, 191 mLauncherComponent); 192 193 // Can't use forEachPackageItem due to the checked exceptions. 194 { 195 final int size = mLaunchers.size(); 196 for (int i = 0; i < size; i++) { 197 saveShortcutPackageItem(s, out, mLaunchers.valueAt(i), forBackup); 198 } 199 } 200 { 201 final int size = mPackages.size(); 202 for (int i = 0; i < size; i++) { 203 saveShortcutPackageItem(s, out, mPackages.valueAt(i), forBackup); 204 } 205 } 206 207 out.endTag(null, TAG_ROOT); 208 } 209 210 private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out, 211 ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException { 212 if (forBackup) { 213 if (!s.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) { 214 return; // Don't save. 215 } 216 if (spi.getPackageUserId() != spi.getOwnerUserId()) { 217 return; // Don't save cross-user information. 218 } 219 } 220 spi.saveToXml(out, forBackup); 221 } 222 223 public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId, 224 boolean fromBackup) throws IOException, XmlPullParserException { 225 final ShortcutUser ret = new ShortcutUser(userId); 226 227 final int outerDepth = parser.getDepth(); 228 int type; 229 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 230 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 231 if (type != XmlPullParser.START_TAG) { 232 continue; 233 } 234 final int depth = parser.getDepth(); 235 final String tag = parser.getName(); 236 237 if (depth == outerDepth + 1) { 238 switch (tag) { 239 case TAG_LAUNCHER: { 240 ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute( 241 parser, ATTR_VALUE); 242 continue; 243 } 244 case ShortcutPackage.TAG_ROOT: { 245 final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml( 246 s, parser, userId, fromBackup); 247 248 // Don't use addShortcut(), we don't need to save the icon. 249 ret.mPackages.put(shortcuts.getPackageName(), shortcuts); 250 continue; 251 } 252 253 case ShortcutLauncher.TAG_ROOT: { 254 ret.addLauncher(ShortcutLauncher.loadFromXml(parser, userId, fromBackup)); 255 continue; 256 } 257 } 258 } 259 ShortcutService.warnForInvalidTag(depth, tag); 260 } 261 return ret; 262 } 263 264 public ComponentName getLauncherComponent() { 265 return mLauncherComponent; 266 } 267 268 public void setLauncherComponent(ShortcutService s, ComponentName launcherComponent) { 269 if (Objects.equal(mLauncherComponent, launcherComponent)) { 270 return; 271 } 272 mLauncherComponent = launcherComponent; 273 s.scheduleSaveUser(mUserId); 274 } 275 276 public void resetThrottling() { 277 for (int i = mPackages.size() - 1; i >= 0; i--) { 278 mPackages.valueAt(i).resetThrottling(); 279 } 280 } 281 282 public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) { 283 pw.print(prefix); 284 pw.print("User: "); 285 pw.print(mUserId); 286 pw.println(); 287 288 prefix += prefix + " "; 289 290 pw.print(prefix); 291 pw.print("Default launcher: "); 292 pw.print(mLauncherComponent); 293 pw.println(); 294 295 for (int i = 0; i < mLaunchers.size(); i++) { 296 mLaunchers.valueAt(i).dump(s, pw, prefix); 297 } 298 299 for (int i = 0; i < mPackages.size(); i++) { 300 mPackages.valueAt(i).dump(s, pw, prefix); 301 } 302 303 pw.println(); 304 pw.print(prefix); 305 pw.println("Bitmap directories: "); 306 dumpDirectorySize(s, pw, prefix + " ", s.getUserBitmapFilePath(mUserId)); 307 } 308 309 private void dumpDirectorySize(@NonNull ShortcutService s, @NonNull PrintWriter pw, 310 @NonNull String prefix, File path) { 311 int numFiles = 0; 312 long size = 0; 313 final File[] children = path.listFiles(); 314 if (children != null) { 315 for (File child : path.listFiles()) { 316 if (child.isFile()) { 317 numFiles++; 318 size += child.length(); 319 } else if (child.isDirectory()) { 320 dumpDirectorySize(s, pw, prefix + " ", child); 321 } 322 } 323 } 324 pw.print(prefix); 325 pw.print("Path: "); 326 pw.print(path.getName()); 327 pw.print("/ has "); 328 pw.print(numFiles); 329 pw.print(" files, size="); 330 pw.print(size); 331 pw.print(" ("); 332 pw.print(Formatter.formatFileSize(s.mContext, size)); 333 pw.println(")"); 334 } 335} 336