Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45e499a3 authored by Håkan Kvist's avatar Håkan Kvist
Browse files

Improve robustness when migrating from appops xml

A device failing to create a complete appops.xml with all the
attributes needed will cause appops migration to fail when upgrading.

AppOpsService is reading its files as part of ActivityManagerService
start, which happens before rescue party is started.

Upon failure Rescue party is not started, there is no attempt to
reboot and the user is stuck with a device trying to boot.
A user experiencing this will think the device is bricked.

This change will log the actual error, treat the appops xml as not
existing instead of throwing an exception.

Bug: 323262109
Test: adb root
    adb shell stop
    adb shell rm /data/misc/apexdata/com.android.permission/access.abx \
        /data/misc_de/0/apexdata/com.android.permission/access.abx
    adb shell dd if=/dev/urandom of=/data/system/appops_accesses.xml \
        bs=4096 count=2
    adb shell dd if=/dev/urandom of=/data/system/appops.xml bs=4096 \
        count=2
    adb shell start
Change-Id: Ic24259662e1c7f0cfe23c72bd1c390f9aff80bec
parent c456bc72
Loading
Loading
Loading
Loading
+1 −11
Original line number Diff line number Diff line
@@ -4973,17 +4973,7 @@ public class AppOpsService extends IAppOpsService.Stub {
                    }

                    success = true;
                } catch (IllegalStateException e) {
                    Slog.w(TAG, "Failed parsing " + e);
                } catch (NullPointerException e) {
                    Slog.w(TAG, "Failed parsing " + e);
                } catch (NumberFormatException e) {
                    Slog.w(TAG, "Failed parsing " + e);
                } catch (XmlPullParserException e) {
                    Slog.w(TAG, "Failed parsing " + e);
                } catch (IOException e) {
                    Slog.w(TAG, "Failed parsing " + e);
                } catch (IndexOutOfBoundsException e) {
                } catch (Exception e) {
                    Slog.w(TAG, "Failed parsing " + e);
                } finally {
                    if (!success) {
+23 −8
Original line number Diff line number Diff line
@@ -50,6 +50,10 @@ class LegacyAppOpStateParser {
    public int readState(AtomicFile file, SparseArray<SparseIntArray> uidModes,
            SparseArray<ArrayMap<String, SparseIntArray>> userPackageModes) {
        try (FileInputStream stream = file.openRead()) {
            SparseArray<SparseIntArray> parsedUidModes = new SparseArray<>();
            SparseArray<ArrayMap<String, SparseIntArray>> parsedUserPackageModes =
                    new SparseArray<>();

            TypedXmlPullParser parser = Xml.resolvePullParser(stream);
            int type;
            while ((type = parser.next()) != XmlPullParser.START_TAG
@@ -75,26 +79,37 @@ class LegacyAppOpStateParser {
                    // version 2 has the structure pkg -> uid -> op ->
                    // in version 3, since pkg and uid states are kept completely
                    // independent we switch to user -> pkg -> op
                    readPackage(parser, userPackageModes);
                    readPackage(parser, parsedUserPackageModes);
                } else if (tagName.equals("uid")) {
                    readUidOps(parser, uidModes);
                    readUidOps(parser, parsedUidModes);
                } else if (tagName.equals("user")) {
                    readUser(parser, userPackageModes);
                    readUser(parser, parsedUserPackageModes);
                } else {
                    Slog.w(TAG, "Unknown element under <app-ops>: "
                            + parser.getName());
                    XmlUtils.skipCurrentTag(parser);
                }
            }

            // Parsing is complete, copy all parsed values to output
            final int parsedUidModesSize = parsedUidModes.size();
            for (int i = 0; i < parsedUidModesSize; i++) {
                uidModes.put(parsedUidModes.keyAt(i), parsedUidModes.valueAt(i));
            }
            final int parsedUserPackageModesSize = parsedUserPackageModes.size();
            for (int i = 0; i < parsedUserPackageModesSize; i++) {
                userPackageModes.put(parsedUserPackageModes.keyAt(i),
                                     parsedUserPackageModes.valueAt(i));
            }

            return versionAtBoot;
        } catch (FileNotFoundException e) {
            Slog.i(TAG, "No existing app ops " + file.getBaseFile() + "; starting empty");
            return NO_FILE_VERSION;
        } catch (XmlPullParserException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            // All exceptions must be caught, otherwise device will not be able to boot
            Slog.wtf(TAG, "Failed parsing " + e);
        }
        return NO_FILE_VERSION;
    }

    private void readPackage(TypedXmlPullParser parser,