blob: 6c3fbc1f4160823d4ddd2f2a08546a286cdd50f4 [file] [log] [blame]
Alan Viveretteb6a25732017-11-21 14:49:24 -05001/*
2 * Copyright (C) 2018 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 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Alan Viveretteb6a25732017-11-21 14:49:24 -050018
19import android.annotation.UiThread;
Wale Ogunwale402de822018-03-22 10:03:06 -070020import android.content.ComponentName;
Alan Viveretteb6a25732017-11-21 14:49:24 -050021import android.content.Context;
22import android.content.res.Configuration;
23import android.os.Build;
24import android.os.Handler;
25import android.os.Looper;
26import android.os.Message;
27import android.util.AtomicFile;
28import android.util.DisplayMetrics;
29import android.util.Slog;
30import android.util.Xml;
31
32import com.android.internal.util.FastXmlSerializer;
33
34import org.xmlpull.v1.XmlPullParser;
35import org.xmlpull.v1.XmlPullParserException;
36import org.xmlpull.v1.XmlSerializer;
37
38import java.io.File;
39import java.io.FileInputStream;
40import java.io.FileOutputStream;
41import java.nio.charset.StandardCharsets;
42import java.util.HashMap;
Wale Ogunwale402de822018-03-22 10:03:06 -070043import java.util.HashSet;
Alan Viveretteb6a25732017-11-21 14:49:24 -050044import java.util.Map;
45
46/**
47 * Manages warning dialogs shown during application lifecycle.
48 */
49class AppWarnings {
50 private static final String TAG = "AppWarnings";
51 private static final String CONFIG_FILE_NAME = "packages-warnings.xml";
52
53 public static final int FLAG_HIDE_DISPLAY_SIZE = 0x01;
54 public static final int FLAG_HIDE_COMPILE_SDK = 0x02;
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +000055 public static final int FLAG_HIDE_DEPRECATED_SDK = 0x04;
Alan Viveretteb6a25732017-11-21 14:49:24 -050056
57 private final HashMap<String, Integer> mPackageFlags = new HashMap<>();
58
Wale Ogunwale008163e2018-07-23 23:11:08 -070059 private final ActivityTaskManagerService mAtm;
Alan Viveretteb6a25732017-11-21 14:49:24 -050060 private final Context mUiContext;
Wale Ogunwale008163e2018-07-23 23:11:08 -070061 private final ConfigHandler mHandler;
Alan Viveretteb6a25732017-11-21 14:49:24 -050062 private final UiHandler mUiHandler;
63 private final AtomicFile mConfigFile;
64
65 private UnsupportedDisplaySizeDialog mUnsupportedDisplaySizeDialog;
66 private UnsupportedCompileSdkDialog mUnsupportedCompileSdkDialog;
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +000067 private DeprecatedTargetSdkVersionDialog mDeprecatedTargetSdkVersionDialog;
Alan Viveretteb6a25732017-11-21 14:49:24 -050068
Wale Ogunwale402de822018-03-22 10:03:06 -070069 /** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
70 private HashSet<ComponentName> mAlwaysShowUnsupportedCompileSdkWarningActivities =
71 new HashSet<>();
72
73 /** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
74 void alwaysShowUnsupportedCompileSdkWarning(ComponentName activity) {
75 mAlwaysShowUnsupportedCompileSdkWarningActivities.add(activity);
76 }
77
Alan Viveretteb6a25732017-11-21 14:49:24 -050078 /**
79 * Creates a new warning dialog manager.
80 * <p>
81 * <strong>Note:</strong> Must be called from the ActivityManagerService thread.
82 *
Wale Ogunwale008163e2018-07-23 23:11:08 -070083 * @param atm
Alan Viveretteb6a25732017-11-21 14:49:24 -050084 * @param uiContext
Wale Ogunwale008163e2018-07-23 23:11:08 -070085 * @param handler
Alan Viveretteb6a25732017-11-21 14:49:24 -050086 * @param uiHandler
87 * @param systemDir
88 */
Wale Ogunwale008163e2018-07-23 23:11:08 -070089 public AppWarnings(ActivityTaskManagerService atm, Context uiContext, Handler handler,
Alan Viveretteb6a25732017-11-21 14:49:24 -050090 Handler uiHandler, File systemDir) {
Wale Ogunwale008163e2018-07-23 23:11:08 -070091 mAtm = atm;
Alan Viveretteb6a25732017-11-21 14:49:24 -050092 mUiContext = uiContext;
Wale Ogunwale008163e2018-07-23 23:11:08 -070093 mHandler = new ConfigHandler(handler.getLooper());
Alan Viveretteb6a25732017-11-21 14:49:24 -050094 mUiHandler = new UiHandler(uiHandler.getLooper());
Dianne Hackborne17b4452018-01-10 13:15:40 -080095 mConfigFile = new AtomicFile(new File(systemDir, CONFIG_FILE_NAME), "warnings-config");
Alan Viveretteb6a25732017-11-21 14:49:24 -050096
97 readConfigFromFileAmsThread();
98 }
99
100 /**
101 * Shows the "unsupported display size" warning, if necessary.
102 *
103 * @param r activity record for which the warning may be displayed
104 */
105 public void showUnsupportedDisplaySizeDialogIfNeeded(ActivityRecord r) {
Wale Ogunwale008163e2018-07-23 23:11:08 -0700106 final Configuration globalConfig = mAtm.getGlobalConfiguration();
Alan Viveretteb6a25732017-11-21 14:49:24 -0500107 if (globalConfig.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE
108 && r.appInfo.requiresSmallestWidthDp > globalConfig.smallestScreenWidthDp) {
109 mUiHandler.showUnsupportedDisplaySizeDialog(r);
110 }
111 }
112
113 /**
114 * Shows the "unsupported compile SDK" warning, if necessary.
115 *
116 * @param r activity record for which the warning may be displayed
117 */
118 public void showUnsupportedCompileSdkDialogIfNeeded(ActivityRecord r) {
119 if (r.appInfo.compileSdkVersion == 0 || r.appInfo.compileSdkVersionCodename == null) {
120 // We don't know enough about this package. Abort!
121 return;
122 }
123
Ian Pedowitz2333f7c2018-04-25 08:57:54 -0700124 // TODO(b/75318890): Need to move this to when the app actually crashes.
Siarhei Vishniakou2830dd72018-04-05 10:35:38 -0700125 if (/*ActivityManager.isRunningInTestHarness()
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800126 &&*/ !mAlwaysShowUnsupportedCompileSdkWarningActivities.contains(
127 r.mActivityComponent)) {
Siarhei Vishniakou2830dd72018-04-05 10:35:38 -0700128 // Don't show warning if we are running in a test harness and we don't have to always
129 // show for this activity.
130 return;
Wale Ogunwale402de822018-03-22 10:03:06 -0700131 }
132
Alan Viveretteb6a25732017-11-21 14:49:24 -0500133 // If the application was built against an pre-release SDK that's older than the current
134 // platform OR if the current platform is pre-release and older than the SDK against which
135 // the application was built OR both are pre-release with the same SDK_INT but different
136 // codenames (e.g. simultaneous pre-release development), then we're likely to run into
137 // compatibility issues. Warn the user and offer to check for an update.
138 final int compileSdk = r.appInfo.compileSdkVersion;
Siarhei Vishniakou2830dd72018-04-05 10:35:38 -0700139 final int platformSdk = Build.VERSION.SDK_INT;
Alan Viveretteb6a25732017-11-21 14:49:24 -0500140 final boolean isCompileSdkPreview = !"REL".equals(r.appInfo.compileSdkVersionCodename);
141 final boolean isPlatformSdkPreview = !"REL".equals(Build.VERSION.CODENAME);
142 if ((isCompileSdkPreview && compileSdk < platformSdk)
143 || (isPlatformSdkPreview && platformSdk < compileSdk)
144 || (isCompileSdkPreview && isPlatformSdkPreview && platformSdk == compileSdk
145 && !Build.VERSION.CODENAME.equals(r.appInfo.compileSdkVersionCodename))) {
146 mUiHandler.showUnsupportedCompileSdkDialog(r);
147 }
148 }
149
150 /**
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +0000151 * Shows the "deprecated target sdk" warning, if necessary.
152 *
153 * @param r activity record for which the warning may be displayed
154 */
155 public void showDeprecatedTargetDialogIfNeeded(ActivityRecord r) {
156 if (r.appInfo.targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT) {
157 mUiHandler.showDeprecatedTargetDialog(r);
158 }
159 }
160
161 /**
Alan Viveretteb6a25732017-11-21 14:49:24 -0500162 * Called when an activity is being started.
163 *
164 * @param r record for the activity being started
165 */
166 public void onStartActivity(ActivityRecord r) {
167 showUnsupportedCompileSdkDialogIfNeeded(r);
168 showUnsupportedDisplaySizeDialogIfNeeded(r);
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +0000169 showDeprecatedTargetDialogIfNeeded(r);
Alan Viveretteb6a25732017-11-21 14:49:24 -0500170 }
171
172 /**
173 * Called when an activity was previously started and is being resumed.
174 *
175 * @param r record for the activity being resumed
176 */
177 public void onResumeActivity(ActivityRecord r) {
178 showUnsupportedDisplaySizeDialogIfNeeded(r);
179 }
180
181 /**
182 * Called by ActivityManagerService when package data has been cleared.
183 *
184 * @param name the package whose data has been cleared
185 */
186 public void onPackageDataCleared(String name) {
187 removePackageAndHideDialogs(name);
188 }
189
190 /**
191 * Called by ActivityManagerService when a package has been uninstalled.
192 *
193 * @param name the package that has been uninstalled
194 */
195 public void onPackageUninstalled(String name) {
196 removePackageAndHideDialogs(name);
197 }
198
199 /**
200 * Called by ActivityManagerService when the default display density has changed.
201 */
202 public void onDensityChanged() {
203 mUiHandler.hideUnsupportedDisplaySizeDialog();
204 }
205
206 /**
207 * Does what it says on the tin.
208 */
209 private void removePackageAndHideDialogs(String name) {
210 mUiHandler.hideDialogsForPackage(name);
211
212 synchronized (mPackageFlags) {
213 mPackageFlags.remove(name);
Wale Ogunwale008163e2018-07-23 23:11:08 -0700214 mHandler.scheduleWrite();
Alan Viveretteb6a25732017-11-21 14:49:24 -0500215 }
216 }
217
218 /**
219 * Hides the "unsupported display size" warning.
220 * <p>
221 * <strong>Note:</strong> Must be called on the UI thread.
222 */
223 @UiThread
224 private void hideUnsupportedDisplaySizeDialogUiThread() {
225 if (mUnsupportedDisplaySizeDialog != null) {
226 mUnsupportedDisplaySizeDialog.dismiss();
227 mUnsupportedDisplaySizeDialog = null;
228 }
229 }
230
231 /**
232 * Shows the "unsupported display size" warning for the given application.
233 * <p>
234 * <strong>Note:</strong> Must be called on the UI thread.
235 *
236 * @param ar record for the activity that triggered the warning
237 */
238 @UiThread
239 private void showUnsupportedDisplaySizeDialogUiThread(ActivityRecord ar) {
240 if (mUnsupportedDisplaySizeDialog != null) {
241 mUnsupportedDisplaySizeDialog.dismiss();
242 mUnsupportedDisplaySizeDialog = null;
243 }
244 if (ar != null && !hasPackageFlag(
245 ar.packageName, FLAG_HIDE_DISPLAY_SIZE)) {
246 mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog(
247 AppWarnings.this, mUiContext, ar.info.applicationInfo);
248 mUnsupportedDisplaySizeDialog.show();
249 }
250 }
251
252 /**
253 * Shows the "unsupported compile SDK" warning for the given application.
254 * <p>
255 * <strong>Note:</strong> Must be called on the UI thread.
256 *
257 * @param ar record for the activity that triggered the warning
258 */
259 @UiThread
260 private void showUnsupportedCompileSdkDialogUiThread(ActivityRecord ar) {
261 if (mUnsupportedCompileSdkDialog != null) {
262 mUnsupportedCompileSdkDialog.dismiss();
263 mUnsupportedCompileSdkDialog = null;
264 }
265 if (ar != null && !hasPackageFlag(
266 ar.packageName, FLAG_HIDE_COMPILE_SDK)) {
267 mUnsupportedCompileSdkDialog = new UnsupportedCompileSdkDialog(
268 AppWarnings.this, mUiContext, ar.info.applicationInfo);
269 mUnsupportedCompileSdkDialog.show();
270 }
271 }
272
273 /**
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +0000274 * Shows the "deprecated target sdk version" warning for the given application.
275 * <p>
276 * <strong>Note:</strong> Must be called on the UI thread.
277 *
278 * @param ar record for the activity that triggered the warning
279 */
280 @UiThread
281 private void showDeprecatedTargetSdkDialogUiThread(ActivityRecord ar) {
282 if (mDeprecatedTargetSdkVersionDialog != null) {
283 mDeprecatedTargetSdkVersionDialog.dismiss();
284 mDeprecatedTargetSdkVersionDialog = null;
285 }
286 if (ar != null && !hasPackageFlag(
287 ar.packageName, FLAG_HIDE_DEPRECATED_SDK)) {
288 mDeprecatedTargetSdkVersionDialog = new DeprecatedTargetSdkVersionDialog(
289 AppWarnings.this, mUiContext, ar.info.applicationInfo);
290 mDeprecatedTargetSdkVersionDialog.show();
291 }
292 }
293
294 /**
Alan Viveretteb6a25732017-11-21 14:49:24 -0500295 * Dismisses all warnings for the given package.
296 * <p>
297 * <strong>Note:</strong> Must be called on the UI thread.
298 *
299 * @param name the package for which warnings should be dismissed, or {@code null} to dismiss
300 * all warnings
301 */
302 @UiThread
303 private void hideDialogsForPackageUiThread(String name) {
304 // Hides the "unsupported display" dialog if necessary.
305 if (mUnsupportedDisplaySizeDialog != null && (name == null || name.equals(
306 mUnsupportedDisplaySizeDialog.getPackageName()))) {
307 mUnsupportedDisplaySizeDialog.dismiss();
308 mUnsupportedDisplaySizeDialog = null;
309 }
310
311 // Hides the "unsupported compile SDK" dialog if necessary.
312 if (mUnsupportedCompileSdkDialog != null && (name == null || name.equals(
313 mUnsupportedCompileSdkDialog.getPackageName()))) {
314 mUnsupportedCompileSdkDialog.dismiss();
315 mUnsupportedCompileSdkDialog = null;
316 }
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +0000317
318 // Hides the "deprecated target sdk version" dialog if necessary.
319 if (mDeprecatedTargetSdkVersionDialog != null && (name == null || name.equals(
320 mDeprecatedTargetSdkVersionDialog.getPackageName()))) {
321 mDeprecatedTargetSdkVersionDialog.dismiss();
322 mDeprecatedTargetSdkVersionDialog = null;
323 }
Alan Viveretteb6a25732017-11-21 14:49:24 -0500324 }
325
326 /**
327 * Returns the value of the flag for the given package.
328 *
329 * @param name the package from which to retrieve the flag
330 * @param flag the bitmask for the flag to retrieve
331 * @return {@code true} if the flag is enabled, {@code false} otherwise
332 */
333 boolean hasPackageFlag(String name, int flag) {
334 return (getPackageFlags(name) & flag) == flag;
335 }
336
337 /**
338 * Sets the flag for the given package to the specified value.
339 *
340 * @param name the package on which to set the flag
341 * @param flag the bitmask for flag to set
342 * @param enabled the value to set for the flag
343 */
344 void setPackageFlag(String name, int flag, boolean enabled) {
345 synchronized (mPackageFlags) {
346 final int curFlags = getPackageFlags(name);
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +0000347 final int newFlags = enabled ? (curFlags | flag) : (curFlags & ~flag);
Alan Viveretteb6a25732017-11-21 14:49:24 -0500348 if (curFlags != newFlags) {
349 if (newFlags != 0) {
350 mPackageFlags.put(name, newFlags);
351 } else {
352 mPackageFlags.remove(name);
353 }
Wale Ogunwale008163e2018-07-23 23:11:08 -0700354 mHandler.scheduleWrite();
Alan Viveretteb6a25732017-11-21 14:49:24 -0500355 }
356 }
357 }
358
359 /**
360 * Returns the bitmask of flags set for the specified package.
361 */
362 private int getPackageFlags(String name) {
363 synchronized (mPackageFlags) {
364 return mPackageFlags.getOrDefault(name, 0);
365 }
366 }
367
368 /**
369 * Handles messages on the system process UI thread.
370 */
371 private final class UiHandler extends Handler {
372 private static final int MSG_SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG = 1;
373 private static final int MSG_HIDE_UNSUPPORTED_DISPLAY_SIZE_DIALOG = 2;
374 private static final int MSG_SHOW_UNSUPPORTED_COMPILE_SDK_DIALOG = 3;
375 private static final int MSG_HIDE_DIALOGS_FOR_PACKAGE = 4;
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +0000376 private static final int MSG_SHOW_DEPRECATED_TARGET_SDK_DIALOG = 5;
Alan Viveretteb6a25732017-11-21 14:49:24 -0500377
378 public UiHandler(Looper looper) {
379 super(looper, null, true);
380 }
381
382 @Override
383 public void handleMessage(Message msg) {
384 switch (msg.what) {
385 case MSG_SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG: {
386 final ActivityRecord ar = (ActivityRecord) msg.obj;
387 showUnsupportedDisplaySizeDialogUiThread(ar);
388 } break;
389 case MSG_HIDE_UNSUPPORTED_DISPLAY_SIZE_DIALOG: {
390 hideUnsupportedDisplaySizeDialogUiThread();
391 } break;
392 case MSG_SHOW_UNSUPPORTED_COMPILE_SDK_DIALOG: {
393 final ActivityRecord ar = (ActivityRecord) msg.obj;
394 showUnsupportedCompileSdkDialogUiThread(ar);
395 } break;
396 case MSG_HIDE_DIALOGS_FOR_PACKAGE: {
397 final String name = (String) msg.obj;
398 hideDialogsForPackageUiThread(name);
399 } break;
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +0000400 case MSG_SHOW_DEPRECATED_TARGET_SDK_DIALOG: {
401 final ActivityRecord ar = (ActivityRecord) msg.obj;
402 showDeprecatedTargetSdkDialogUiThread(ar);
403 } break;
Alan Viveretteb6a25732017-11-21 14:49:24 -0500404 }
405 }
406
407 public void showUnsupportedDisplaySizeDialog(ActivityRecord r) {
408 removeMessages(MSG_SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG);
409 obtainMessage(MSG_SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG, r).sendToTarget();
410 }
411
412 public void hideUnsupportedDisplaySizeDialog() {
413 removeMessages(MSG_HIDE_UNSUPPORTED_DISPLAY_SIZE_DIALOG);
414 sendEmptyMessage(MSG_HIDE_UNSUPPORTED_DISPLAY_SIZE_DIALOG);
415 }
416
417 public void showUnsupportedCompileSdkDialog(ActivityRecord r) {
418 removeMessages(MSG_SHOW_UNSUPPORTED_COMPILE_SDK_DIALOG);
419 obtainMessage(MSG_SHOW_UNSUPPORTED_COMPILE_SDK_DIALOG, r).sendToTarget();
420 }
421
Przemyslaw Szczepaniakce73c7e2018-01-22 11:00:41 +0000422 public void showDeprecatedTargetDialog(ActivityRecord r) {
423 removeMessages(MSG_SHOW_DEPRECATED_TARGET_SDK_DIALOG);
424 obtainMessage(MSG_SHOW_DEPRECATED_TARGET_SDK_DIALOG, r).sendToTarget();
425 }
426
Alan Viveretteb6a25732017-11-21 14:49:24 -0500427 public void hideDialogsForPackage(String name) {
428 obtainMessage(MSG_HIDE_DIALOGS_FOR_PACKAGE, name).sendToTarget();
429 }
430 }
431
432 /**
Wale Ogunwale008163e2018-07-23 23:11:08 -0700433 * Handles messages on the ActivityTaskManagerService thread.
Alan Viveretteb6a25732017-11-21 14:49:24 -0500434 */
435 private final class ConfigHandler extends Handler {
Wale Ogunwale008163e2018-07-23 23:11:08 -0700436 private static final int MSG_WRITE = 1;
Alan Viveretteb6a25732017-11-21 14:49:24 -0500437
438 private static final int DELAY_MSG_WRITE = 10000;
439
440 public ConfigHandler(Looper looper) {
441 super(looper, null, true);
442 }
443
444 @Override
445 public void handleMessage(Message msg) {
446 switch (msg.what) {
447 case MSG_WRITE:
448 writeConfigToFileAmsThread();
449 break;
450 }
451 }
452
453 public void scheduleWrite() {
454 removeMessages(MSG_WRITE);
455 sendEmptyMessageDelayed(MSG_WRITE, DELAY_MSG_WRITE);
456 }
457 }
458
459 /**
460 * Writes the configuration file.
461 * <p>
462 * <strong>Note:</strong> Should be called from the ActivityManagerService thread unless you
463 * don't care where you're doing I/O operations. But you <i>do</i> care, don't you?
464 */
465 private void writeConfigToFileAmsThread() {
466 // Create a shallow copy so that we don't have to synchronize on config.
467 final HashMap<String, Integer> packageFlags;
468 synchronized (mPackageFlags) {
469 packageFlags = new HashMap<>(mPackageFlags);
470 }
471
472 FileOutputStream fos = null;
473 try {
474 fos = mConfigFile.startWrite();
475
476 final XmlSerializer out = new FastXmlSerializer();
477 out.setOutput(fos, StandardCharsets.UTF_8.name());
478 out.startDocument(null, true);
479 out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
480 out.startTag(null, "packages");
481
482 for (Map.Entry<String, Integer> entry : packageFlags.entrySet()) {
483 String pkg = entry.getKey();
484 int mode = entry.getValue();
485 if (mode == 0) {
486 continue;
487 }
488 out.startTag(null, "package");
489 out.attribute(null, "name", pkg);
490 out.attribute(null, "flags", Integer.toString(mode));
491 out.endTag(null, "package");
492 }
493
494 out.endTag(null, "packages");
495 out.endDocument();
496
497 mConfigFile.finishWrite(fos);
498 } catch (java.io.IOException e1) {
499 Slog.w(TAG, "Error writing package metadata", e1);
500 if (fos != null) {
501 mConfigFile.failWrite(fos);
502 }
503 }
504 }
505
506 /**
507 * Reads the configuration file and populates the package flags.
508 * <p>
509 * <strong>Note:</strong> Must be called from the constructor (and thus on the
510 * ActivityManagerService thread) since we don't synchronize on config.
511 */
512 private void readConfigFromFileAmsThread() {
513 FileInputStream fis = null;
514
515 try {
516 fis = mConfigFile.openRead();
517
518 final XmlPullParser parser = Xml.newPullParser();
519 parser.setInput(fis, StandardCharsets.UTF_8.name());
520
521 int eventType = parser.getEventType();
522 while (eventType != XmlPullParser.START_TAG &&
523 eventType != XmlPullParser.END_DOCUMENT) {
524 eventType = parser.next();
525 }
526 if (eventType == XmlPullParser.END_DOCUMENT) {
527 return;
528 }
529
530 String tagName = parser.getName();
531 if ("packages".equals(tagName)) {
532 eventType = parser.next();
533 do {
534 if (eventType == XmlPullParser.START_TAG) {
535 tagName = parser.getName();
536 if (parser.getDepth() == 2) {
537 if ("package".equals(tagName)) {
538 final String name = parser.getAttributeValue(null, "name");
539 if (name != null) {
540 final String flags = parser.getAttributeValue(
541 null, "flags");
542 int flagsInt = 0;
543 if (flags != null) {
544 try {
545 flagsInt = Integer.parseInt(flags);
546 } catch (NumberFormatException e) {
547 }
548 }
549 mPackageFlags.put(name, flagsInt);
550 }
551 }
552 }
553 }
554 eventType = parser.next();
555 } while (eventType != XmlPullParser.END_DOCUMENT);
556 }
557 } catch (XmlPullParserException e) {
558 Slog.w(TAG, "Error reading package metadata", e);
559 } catch (java.io.IOException e) {
560 if (fis != null) Slog.w(TAG, "Error reading package metadata", e);
561 } finally {
562 if (fis != null) {
563 try {
564 fis.close();
565 } catch (java.io.IOException e1) {
566 }
567 }
568 }
569 }
570}