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

Commit 53db794b authored by Ivan Chiang's avatar Ivan Chiang
Browse files

[PM] Add APK-in-APEX info in ModuleInfo

Bug: 306329516
Test: Let provide_info_of_apk_in_apex true on the device && atest
PackageManagerTest ModuleInfoTest

Change-Id: I71d265421176ab515f4a27ffbb8cbddd3d075fed
parent c15578db
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12368,6 +12368,7 @@ package android.content.pm {
  public final class ModuleInfo implements android.os.Parcelable {
    method public int describeContents();
    method @FlaggedApi("android.content.pm.provide_info_of_apk_in_apex") @NonNull public java.util.Collection<java.lang.String> getApkInApexPackageNames();
    method @Nullable public CharSequence getName();
    method @Nullable public String getPackageName();
    method public boolean isHidden();
+39 −0
Original line number Diff line number Diff line
@@ -16,10 +16,15 @@

package android.content.pm;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
@@ -46,6 +51,13 @@ public final class ModuleInfo implements Parcelable {
    /** Whether or not this module is hidden from the user. */
    private boolean mHidden;

    /**
     * The list of the package names of all APK-in-APEX apps in the module, or
     * null if there are none.
     */
    @Nullable
    private List<String> mApkInApexPackageNames;

    // TODO: Decide whether we need an additional metadata bundle to support out of band
    // updates to ModuleInfo.
    //
@@ -61,6 +73,9 @@ public final class ModuleInfo implements Parcelable {
        mPackageName = orig.mPackageName;
        mHidden = orig.mHidden;
        mApexModuleName = orig.mApexModuleName;
        if (orig.mApkInApexPackageNames != null) {
            mApkInApexPackageNames = List.copyOf(orig.mApkInApexPackageNames);
        }
    }

    /** @hide Sets the public name of this module. */
@@ -107,6 +122,25 @@ public final class ModuleInfo implements Parcelable {
        return mApexModuleName;
    }

    /** @hide Sets the list of the package name of APK-in-APEX apps in this module. */
    public ModuleInfo setApkInApexPackageNames(@NonNull Collection<String> apkInApexPackageNames) {
        Objects.requireNonNull(apkInApexPackageNames);
        mApkInApexPackageNames = List.copyOf(apkInApexPackageNames);
        return this;
    }

    /**
     * Gets the list of the package name of all APK-in-APEX apps in the module.
     */
    @NonNull
    @FlaggedApi(android.content.pm.Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX)
    public Collection<String> getApkInApexPackageNames() {
        if (mApkInApexPackageNames == null) {
            return Collections.emptyList();
        }
        return mApkInApexPackageNames;
    }

    /** Returns a string representation of this object. */
    public String toString() {
        return "ModuleInfo{"
@@ -125,6 +159,7 @@ public final class ModuleInfo implements Parcelable {
        hashCode = 31 * hashCode + Objects.hashCode(mName);
        hashCode = 31 * hashCode + Objects.hashCode(mPackageName);
        hashCode = 31 * hashCode + Objects.hashCode(mApexModuleName);
        hashCode = 31 * hashCode + Objects.hashCode(mApkInApexPackageNames);
        hashCode = 31 * hashCode + Boolean.hashCode(mHidden);
        return hashCode;
    }
@@ -138,6 +173,7 @@ public final class ModuleInfo implements Parcelable {
        return Objects.equals(mName, other.mName)
                && Objects.equals(mPackageName, other.mPackageName)
                && Objects.equals(mApexModuleName, other.mApexModuleName)
                && Objects.equals(mApkInApexPackageNames, other.mApkInApexPackageNames)
                && mHidden == other.mHidden;
    }

@@ -147,6 +183,8 @@ public final class ModuleInfo implements Parcelable {
        dest.writeString(mPackageName);
        dest.writeBoolean(mHidden);
        dest.writeString(mApexModuleName);
        // Parcel#writeStringList handles null case, we can use it directly
        dest.writeStringList(mApkInApexPackageNames);
    }

    private ModuleInfo(Parcel source) {
@@ -154,6 +192,7 @@ public final class ModuleInfo implements Parcelable {
        mPackageName = source.readString();
        mHidden = source.readBoolean();
        mApexModuleName = source.readString();
        mApkInApexPackageNames = source.createStringArrayList();
    }

    public static final @android.annotation.NonNull Parcelable.Creator<ModuleInfo> CREATOR =
+99 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 android.os.Parcel;
import android.platform.test.annotations.AppModeFull;
import android.text.TextUtils;

import androidx.test.runner.AndroidJUnit4;

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

import java.util.List;

@RunWith(AndroidJUnit4.class)
@AppModeFull
public class ModuleInfoTest {

    private static final String APEX_MODULE_NAME = "apexModuleName";
    private static final String APK_IN_APEX_PACKAGE_NAME = "apkInApexPackageName";
    private static final String MODULE_PACKAGE_NAME = "modulePackageName";
    private static final String MODULE_NAME = "moduleName";

    @Test
    public void testSimple() {
        ModuleInfo info = new ModuleInfo();
        assertThat(info.toString()).isNotNull();
    }

    @Test
    public void testDefaultCopy() {
        ModuleInfo oldInfo = new ModuleInfo();
        ModuleInfo newInfo = new ModuleInfo(oldInfo);
        assertThat(newInfo).isEqualTo(oldInfo);
    }

    @Test
    public void testCopy() {
        boolean isHidden = false;
        ModuleInfo info = new ModuleInfo();
        info.setHidden(isHidden);
        info.setApexModuleName(APEX_MODULE_NAME);
        info.setPackageName(MODULE_PACKAGE_NAME);
        info.setName(MODULE_NAME);
        info.setApkInApexPackageNames(List.of(APK_IN_APEX_PACKAGE_NAME));

        ModuleInfo newInfo = new ModuleInfo(info);
        assertThat(newInfo).isEqualTo(info);
    }

    @Test
    public void testGetApkInApexPackageNamesReturnEmptyListInDefault() {
        ModuleInfo info = new ModuleInfo();
        assertThat(info.getApkInApexPackageNames()).isNotNull();
        assertThat(info.getApkInApexPackageNames()).isEmpty();
    }

    @Test
    public void testModuleInfoParcelizeDeparcelize() {
        boolean isHidden = false;
        ModuleInfo info = new ModuleInfo();
        info.setHidden(isHidden);
        info.setApexModuleName(APEX_MODULE_NAME);
        info.setPackageName(MODULE_PACKAGE_NAME);
        info.setName(MODULE_NAME);
        info.setApkInApexPackageNames(List.of(APK_IN_APEX_PACKAGE_NAME));

        final Parcel p = Parcel.obtain();
        info.writeToParcel(p, 0);
        p.setDataPosition(0);

        final ModuleInfo targetInfo = ModuleInfo.CREATOR.createFromParcel(p);
        p.recycle();

        assertThat(info.isHidden()).isEqualTo(targetInfo.isHidden());
        assertThat(info.getApexModuleName()).isEqualTo(targetInfo.getApexModuleName());
        assertThat(info.getPackageName()).isEqualTo(targetInfo.getPackageName());
        assertThat(TextUtils.equals(info.getName(), targetInfo.getName())).isTrue();
        assertThat(info.getApkInApexPackageNames().toArray()).isEqualTo(
                targetInfo.getApkInApexPackageNames().toArray());
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.pm;

import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.Flags;
import android.content.pm.IPackageManager;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
@@ -165,6 +166,10 @@ public class ModuleInfoProvider {
                mi.setApexModuleName(
                        mApexManager.getApexModuleNameForPackageName(modulePackageName));

                if (Flags.provideInfoOfApkInApex()) {
                    mi.setApkInApexPackageNames(mApexManager.getApksInApex(modulePackageName));
                }

                mModuleInfo.put(modulePackageName, mi);
            }
        } catch (XmlPullParserException | IOException e) {