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

Commit d150569b authored by Rhed Jao's avatar Rhed Jao
Browse files

Fix PackageManager did not recognize OTA when only upgrade product

- Introduce the PackagePartitions.FINGERPRINT to represent the
  fingerprint of the build and all system partitions. Using it to
  determine whether the system update has occurred.

- Update PackageManager relating modules to replace Build.FINGERPRINT
  with the PackagePartitions.FINGERPRINT.

Bug: 135224411
Test: atest PackagePartitionsTest
Change-Id: I4c6244cd71cd0954b4d551f62b81b6ce3e2c4b17
parent 8181f28f
Loading
Loading
Loading
Loading
+56 −8
Original line number Diff line number Diff line
@@ -19,8 +19,11 @@ package android.content.pm;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Build;
import android.os.Build.Partition;
import android.os.Environment;
import android.os.FileUtils;
import android.os.SystemProperties;

import com.android.internal.annotations.VisibleForTesting;

@@ -64,19 +67,33 @@ public class PackagePartitions {
     */
    private static final ArrayList<SystemPartition> SYSTEM_PARTITIONS =
            new ArrayList<>(Arrays.asList(
                    new SystemPartition(Environment.getRootDirectory(), PARTITION_SYSTEM,
                    new SystemPartition(Environment.getRootDirectory(),
                            PARTITION_SYSTEM, Partition.PARTITION_NAME_SYSTEM,
                            true /* containsPrivApp */, false /* containsOverlay */),
                    new SystemPartition(Environment.getVendorDirectory(), PARTITION_VENDOR,
                    new SystemPartition(Environment.getVendorDirectory(),
                            PARTITION_VENDOR, Partition.PARTITION_NAME_VENDOR,
                            true /* containsPrivApp */, true /* containsOverlay */),
                    new SystemPartition(Environment.getOdmDirectory(), PARTITION_ODM,
                    new SystemPartition(Environment.getOdmDirectory(),
                            PARTITION_ODM, Partition.PARTITION_NAME_ODM,
                            true /* containsPrivApp */, true /* containsOverlay */),
                    new SystemPartition(Environment.getOemDirectory(), PARTITION_OEM,
                    new SystemPartition(Environment.getOemDirectory(),
                            PARTITION_OEM, Partition.PARTITION_NAME_OEM,
                            false /* containsPrivApp */, true /* containsOverlay */),
                    new SystemPartition(Environment.getProductDirectory(), PARTITION_PRODUCT,
                    new SystemPartition(Environment.getProductDirectory(),
                            PARTITION_PRODUCT, Partition.PARTITION_NAME_PRODUCT,
                            true /* containsPrivApp */, true /* containsOverlay */),
                    new SystemPartition(Environment.getSystemExtDirectory(), PARTITION_SYSTEM_EXT,
                    new SystemPartition(Environment.getSystemExtDirectory(),
                            PARTITION_SYSTEM_EXT, Partition.PARTITION_NAME_SYSTEM_EXT,
                            true /* containsPrivApp */, true /* containsOverlay */)));

    /**
     * A string to represent the fingerprint of this build and all package partitions. Using it to
     * determine whether the system update has occurred. Different from {@link Build#FINGERPRINT},
     * this string is digested from the fingerprints of the build and all package partitions to
     * help detect the partition update.
     */
    public static final String FINGERPRINT = getFingerprint();

    /**
     * Returns a list in which the elements are products of the specified function applied to the
     * list of {@link #SYSTEM_PARTITIONS} in increasing specificity order.
@@ -101,12 +118,32 @@ public class PackagePartitions {
        }
    }

    /**
     * Returns a fingerprint string for this build and all package partitions. The string is
     * digested from the fingerprints of the build and all package partitions.
     *
     * @return A string to represent the fingerprint of this build and all package partitions.
     */
    @NonNull
    private static String getFingerprint() {
        final String[] digestProperties = new String[SYSTEM_PARTITIONS.size() + 1];
        for (int i = 0; i < SYSTEM_PARTITIONS.size(); i++) {
            final String partitionName = SYSTEM_PARTITIONS.get(i).getName();
            digestProperties[i] = "ro." + partitionName + ".build.fingerprint";
        }
        digestProperties[SYSTEM_PARTITIONS.size()] = "ro.build.fingerprint"; // build fingerprint
        return SystemProperties.digestOf(digestProperties);
    }

    /** Represents a partition that contains application packages. */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    public static class SystemPartition {
        @PartitionType
        public final int type;

        @NonNull
        private final String mName;

        @NonNull
        private final DeferredCanonicalFile mFolder;

@@ -122,9 +159,10 @@ public class PackagePartitions {
        @NonNull
        private final File mNonConicalFolder;

        private SystemPartition(@NonNull File folder, @PartitionType int type,
        private SystemPartition(@NonNull File folder, @PartitionType int type, String name,
                boolean containsPrivApp, boolean containsOverlay) {
            this.type = type;
            this.mName = name;
            this.mFolder = new DeferredCanonicalFile(folder);
            this.mAppFolder = new DeferredCanonicalFile(folder, "app");
            this.mPrivAppFolder = containsPrivApp ? new DeferredCanonicalFile(folder, "priv-app")
@@ -136,6 +174,7 @@ public class PackagePartitions {

        public SystemPartition(@NonNull SystemPartition original) {
            this.type = original.type;
            this.mName = original.mName;
            this.mFolder = new DeferredCanonicalFile(original.mFolder.getFile());
            this.mAppFolder = original.mAppFolder;
            this.mPrivAppFolder = original.mPrivAppFolder;
@@ -148,10 +187,19 @@ public class PackagePartitions {
         * different root folder.
         */
        public SystemPartition(@NonNull File rootFolder, @NonNull SystemPartition partition) {
            this(rootFolder, partition.type, partition.mPrivAppFolder != null,
            this(rootFolder, partition.type, partition.mName, partition.mPrivAppFolder != null,
                    partition.mOverlayFolder != null);
        }

        /**
         * Returns the name identifying the partition.
         * @see Partition
         */
        @NonNull
        public String getName() {
            return mName;
        }

        /** Returns the canonical folder of the partition. */
        @NonNull
        public File getFolder() {
+18 −2
Original line number Diff line number Diff line
@@ -1294,6 +1294,18 @@ public class Build {
    public static class Partition {
        /** The name identifying the system partition. */
        public static final String PARTITION_NAME_SYSTEM = "system";
        /** @hide */
        public static final String PARTITION_NAME_BOOTIMAGE = "bootimage";
        /** @hide */
        public static final String PARTITION_NAME_ODM = "odm";
        /** @hide */
        public static final String PARTITION_NAME_OEM = "oem";
        /** @hide */
        public static final String PARTITION_NAME_PRODUCT = "product";
        /** @hide */
        public static final String PARTITION_NAME_SYSTEM_EXT = "system_ext";
        /** @hide */
        public static final String PARTITION_NAME_VENDOR = "vendor";

        private final String mName;
        private final String mFingerprint;
@@ -1350,8 +1362,12 @@ public class Build {
        ArrayList<Partition> partitions = new ArrayList();

        String[] names = new String[] {
            "bootimage", "odm", "product", "system_ext", Partition.PARTITION_NAME_SYSTEM,
            "vendor"
                Partition.PARTITION_NAME_BOOTIMAGE,
                Partition.PARTITION_NAME_ODM,
                Partition.PARTITION_NAME_PRODUCT,
                Partition.PARTITION_NAME_SYSTEM_EXT,
                Partition.PARTITION_NAME_SYSTEM,
                Partition.PARTITION_NAME_VENDOR
        };
        for (String name : names) {
            String fingerprint = SystemProperties.get("ro." + name + ".build.fingerprint");
+49 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.pm;

import static com.google.common.truth.Truth.assertThat;

import static java.util.function.Function.identity;

import android.content.pm.PackagePartitions.SystemPartition;
import android.os.SystemProperties;

import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.ArrayList;

@RunWith(AndroidJUnit4.class)
public class PackagePartitionsTest {

    @Test
    public void testPackagePartitionsFingerprint() {
        final ArrayList<SystemPartition> partitions = PackagePartitions.getOrderedPartitions(
                identity());
        final String[] properties = new String[partitions.size() + 1];
        for (int i = 0; i < partitions.size(); i++) {
            final String name = partitions.get(i).getName();
            properties[i] = "ro." + name + ".build.fingerprint";
        }
        properties[partitions.size()] = "ro.build.fingerprint";

        assertThat(SystemProperties.digestOf(properties)).isEqualTo(PackagePartitions.FINGERPRINT);
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -67,10 +67,10 @@ import android.content.Intent;
import android.content.PermissionChecker;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackagePartitions;
import android.content.pm.UserInfo;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -716,7 +716,7 @@ class UserController implements Handler.Callback {
        // purposefully block sending BOOT_COMPLETED until after all
        // PRE_BOOT receivers are finished to avoid ANR'ing apps
        final UserInfo info = getUserInfo(userId);
        if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)
        if (!Objects.equals(info.lastLoggedInFingerprint, PackagePartitions.FINGERPRINT)
                || SystemProperties.getBoolean("persist.pm.mock-upgrade", false)) {
            // Suppress double notifications for managed profiles that
            // were unlocked automatically as part of their parent user
+7 −6
Original line number Diff line number Diff line
@@ -1493,8 +1493,8 @@ public class PackageManagerService extends IPackageManager.Stub
        }

        PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
                Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
                Build.VERSION.INCREMENTAL, SNAPSHOT_ENABLED);
                PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG,
                Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL, SNAPSHOT_ENABLED);
        t.traceEnd(); // "create package manager"

        final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
@@ -1904,8 +1904,8 @@ public class PackageManagerService extends IPackageManager.Stub
            mIsUpgrade =
                    !buildFingerprint.equals(ver.fingerprint);
            if (mIsUpgrade) {
                PackageManagerServiceUtils.logCriticalInfo(Log.INFO,
                        "Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
                PackageManagerServiceUtils.logCriticalInfo(Log.INFO, "Upgrading from "
                        + ver.fingerprint + " to " + PackagePartitions.FINGERPRINT);
            }

            // when upgrading from pre-M, promote system app permissions from install to runtime
@@ -2003,7 +2003,8 @@ public class PackageManagerService extends IPackageManager.Stub
            // this situation.
            if (mIsUpgrade) {
                Slog.i(TAG, "Build fingerprint changed from " + ver.fingerprint + " to "
                        + Build.FINGERPRINT + "; regranting permissions for internal storage");
                        + PackagePartitions.FINGERPRINT
                        + "; regranting permissions for internal storage");
            }
            mPermissionManager.onStorageVolumeMounted(
                    StorageManager.UUID_PRIVATE_INTERNAL, mIsUpgrade);
@@ -2037,7 +2038,7 @@ public class PackageManagerService extends IPackageManager.Stub
                                        | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
                    }
                }
                ver.fingerprint = Build.FINGERPRINT;
                ver.fingerprint = PackagePartitions.FINGERPRINT;
            }

            // Legacy existing (installed before Q) non-system apps to hide
Loading