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

Commit 5eb60ccf authored by Yanting Yang's avatar Yanting Yang Committed by Android (Google) Code Review
Browse files

Merge "Hide hidden apk-in-Apex of mainline modules from the app list" into main

parents 404ed228 6c552d6e
Loading
Loading
Loading
Loading
+13 −9
Original line number Diff line number Diff line
@@ -17,10 +17,11 @@
package com.android.settingslib.spaprivileged.model.app

import android.content.Context
import android.content.pm.FeatureFlags
import android.content.pm.FeatureFlagsImpl
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.FeatureFlags
import android.content.pm.FeatureFlagsImpl
import android.content.pm.Flags
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ApplicationInfoFlags
import android.content.pm.ResolveInfo
@@ -85,13 +86,7 @@ class AppListRepositoryImpl(
        loadInstantApps: Boolean,
        matchAnyUserForAdmin: Boolean,
    ): List<ApplicationInfo> = coroutineScope {
        val hiddenSystemModulesDeferred = async {
            packageManager.getInstalledModules(0)
                .filter { it.isHidden }
                .map { it.packageName }
                .filterNotNull()
                .toSet()
        }
        val hiddenSystemModulesDeferred = async { packageManager.getHiddenSystemModules() }
        val hideWhenDisabledPackagesDeferred = async {
            context.resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)
        }
@@ -205,6 +200,15 @@ class AppListRepositoryImpl(
    private fun isSystemApp(app: ApplicationInfo, homeOrLauncherPackages: Set<String>): Boolean =
        app.isSystemApp && !app.isUpdatedSystemApp && app.packageName !in homeOrLauncherPackages

    private fun PackageManager.getHiddenSystemModules(): Set<String> {
        val moduleInfos = getInstalledModules(0).filter { it.isHidden }
        val hiddenApps = moduleInfos.mapNotNull { it.packageName }.toMutableSet()
        if (Flags.provideInfoOfApkInApex()) {
            hiddenApps += moduleInfos.flatMap { it.apkInApexPackageNames }
        }
        return hiddenApps
    }

    companion object {
        private fun ApplicationInfo.isInAppList(
            showInstantApps: Boolean,
+1 −0
Original line number Diff line number Diff line
@@ -35,5 +35,6 @@ android_test {
        "androidx.test.ext.junit",
        "androidx.test.runner",
        "mockito-target-minus-junit4",
        "flag-junit",
    ],
}
+52 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.pm.FakeFeatureFlagsImpl
import android.content.pm.Flags
import android.content.pm.ModuleInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.ApplicationInfoFlags
import android.content.pm.PackageManager.ResolveInfoFlags
@@ -28,6 +29,7 @@ import android.content.pm.ResolveInfo
import android.content.pm.UserInfo
import android.content.res.Resources
import android.os.UserManager
import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.internal.R
@@ -35,6 +37,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
@@ -50,6 +53,9 @@ import org.mockito.kotlin.whenever

@RunWith(AndroidJUnit4::class)
class AppListRepositoryTest {
    @get:Rule
    val mSetFlagsRule = SetFlagsRule()

    private val resources = mock<Resources> {
        on { getStringArray(R.array.config_hideWhenDisabled_packageNames) } doReturn emptyArray()
    }
@@ -272,6 +278,38 @@ class AppListRepositoryTest {
        )
    }

    @Test
    fun loadApps_hasApkInApexInfo_shouldNotIncludeAllHiddenApps() = runTest {
        mSetFlagsRule.enableFlags(Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX)
        packageManager.stub {
            on { getInstalledModules(any()) } doReturn listOf(HIDDEN_MODULE)
        }
        mockInstalledApplications(
            listOf(NORMAL_APP, HIDDEN_APEX_APP, HIDDEN_MODULE_APP),
            ADMIN_USER_ID
        )

        val appList = repository.loadApps(userId = ADMIN_USER_ID)

        assertThat(appList).containsExactly(NORMAL_APP)
    }

    @Test
    fun loadApps_noApkInApexInfo_shouldNotIncludeHiddenSystemModule() = runTest {
        mSetFlagsRule.disableFlags(Flags.FLAG_PROVIDE_INFO_OF_APK_IN_APEX)
        packageManager.stub {
            on { getInstalledModules(any()) } doReturn listOf(HIDDEN_MODULE)
        }
        mockInstalledApplications(
            listOf(NORMAL_APP, HIDDEN_APEX_APP, HIDDEN_MODULE_APP),
            ADMIN_USER_ID
        )

        val appList = repository.loadApps(userId = ADMIN_USER_ID)

        assertThat(appList).containsExactly(NORMAL_APP, HIDDEN_APEX_APP)
    }

    @Test
    fun showSystemPredicate_showSystem() = runTest {
        val app = SYSTEM_APP
@@ -402,6 +440,20 @@ class AppListRepositoryTest {
            isArchived = true
        }

        val HIDDEN_APEX_APP = ApplicationInfo().apply {
            packageName = "hidden.apex.package"
        }

        val HIDDEN_MODULE_APP = ApplicationInfo().apply {
            packageName = "hidden.module.package"
        }

        val HIDDEN_MODULE = ModuleInfo().apply {
            packageName = "hidden.module.package"
            apkInApexPackageNames = listOf("hidden.apex.package")
            isHidden = true
        }

        fun resolveInfoOf(packageName: String) = ResolveInfo().apply {
            activityInfo = ActivityInfo().apply {
                this.packageName = packageName
+11 −6
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.Flags;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -164,12 +165,16 @@ public class AppUtils {

        try {
            final PackageInfo pkg = pm.getPackageInfo(packageName, 0 /* flags */);
            if (Flags.provideInfoOfApkInApex()) {
                return pkg.getApexPackageName() != null;
            } else {
                // Check if the package is contained in an APEX. There is no public API to properly
                // check whether a given APK package comes from an APEX registered as module.
                // Therefore we conservatively assume that any package scanned from an /apex path is
                // a system package.
                return pkg.applicationInfo.sourceDir.startsWith(
                        Environment.getApexDirectory().getAbsolutePath());
            }
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
+6 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.Flags;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.ModuleInfo;
@@ -226,6 +227,11 @@ public class ApplicationsState {
        final List<ModuleInfo> moduleInfos = mPm.getInstalledModules(0 /* flags */);
        for (ModuleInfo info : moduleInfos) {
            mSystemModules.put(info.getPackageName(), info.isHidden());
            if (Flags.provideInfoOfApkInApex()) {
                for (String apkInApexPackageName : info.getApkInApexPackageNames()) {
                    mSystemModules.put(apkInApexPackageName, info.isHidden());
                }
            }
        }

        /**
Loading