Merge "Improve installer attribution in App Info." into sc-dev

This commit is contained in:
Edward Cunningham
2021-04-02 16:44:03 +00:00
committed by Android (Google) Code Review
4 changed files with 144 additions and 32 deletions

View File

@@ -18,6 +18,9 @@ package com.android.settings.applications;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.util.Log;
@@ -31,15 +34,30 @@ public class AppStoreUtil {
.setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
}
// Returns the package name of the app which installed a given packageName, if one is
// available.
// Returns the package name of the app that we consider to be the user-visible 'installer'
// of given packageName, if one is available.
public static String getInstallerPackageName(Context context, String packageName) {
String installerPackageName = null;
String installerPackageName;
try {
installerPackageName =
context.getPackageManager().getInstallerPackageName(packageName);
} catch (IllegalArgumentException e) {
InstallSourceInfo source =
context.getPackageManager().getInstallSourceInfo(packageName);
// By default, use the installing package name.
installerPackageName = source.getInstallingPackageName();
// Use the recorded originating package name only if the initiating package is a system
// app (eg. Package Installer). The originating package is not verified by the platform,
// so we choose to ignore this when supplied by a non-system app.
String originatingPackageName = source.getOriginatingPackageName();
String initiatingPackageName = source.getInitiatingPackageName();
if (originatingPackageName != null && initiatingPackageName != null) {
ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
initiatingPackageName, 0);
if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
installerPackageName = originatingPackageName;
}
}
} catch (NameNotFoundException e) {
Log.e(LOG_TAG, "Exception while retrieving the package installer of " + packageName, e);
installerPackageName = null;
}
return installerPackageName;
}

View File

@@ -0,0 +1,96 @@
/*
* 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 com.android.settings.applications;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class AppStoreUtilTest {
private static final String PACKAGE_NAME = "com.android.app";
private static final String INSTALLING_PACKAGE_NAME = "com.android.installing";
private static final String INITIATING_PACKAGE_NAME = "com.android.initiating";
private static final String ORIGINATING_PACKAGE_NAME = "com.android.originating";
@Mock
private PackageManager mPackageManager;
@Mock
private ApplicationInfo mInitiatingAppInfo;
@Mock
private InstallSourceInfo mInstallSourceInfo;
private Context mContext;
@Before
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
when(mInstallSourceInfo.getInstallingPackageName()).thenReturn(INSTALLING_PACKAGE_NAME);
when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn(INITIATING_PACKAGE_NAME);
when(mInstallSourceInfo.getOriginatingPackageName()).thenReturn(ORIGINATING_PACKAGE_NAME);
when(mPackageManager.getApplicationInfo(eq(INITIATING_PACKAGE_NAME), anyInt()))
.thenReturn(mInitiatingAppInfo);
}
@Test
public void getInstallerPackageName_hasOriginatingByNonSystem_shouldReturnInstalling() {
assertThat(AppStoreUtil.getInstallerPackageName(mContext, PACKAGE_NAME))
.isEqualTo(INSTALLING_PACKAGE_NAME);
}
@Test
public void getInstallerPackageName_hasOriginatingBySystem_shouldReturnOriginating() {
mInitiatingAppInfo.flags = ApplicationInfo.FLAG_SYSTEM;
assertThat(AppStoreUtil.getInstallerPackageName(mContext, PACKAGE_NAME))
.isEqualTo(ORIGINATING_PACKAGE_NAME);
}
@Test
public void getInstallerPackageName_noInitiating_shouldReturnInstalling() {
when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn(null);
assertThat(AppStoreUtil.getInstallerPackageName(mContext, PACKAGE_NAME))
.isEqualTo(INSTALLING_PACKAGE_NAME);
}
@Test
public void getInstallerPackageName_noOriginating_shouldReturnInstalling() {
when(mInstallSourceInfo.getOriginatingPackageName()).thenReturn(null);
assertThat(AppStoreUtil.getInstallerPackageName(mContext, PACKAGE_NAME))
.isEqualTo(INSTALLING_PACKAGE_NAME);
}
}

View File

@@ -32,6 +32,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -60,6 +61,8 @@ public class AppInstallerInfoPreferenceControllerTest {
@Mock
private ApplicationInfo mAppInfo;
@Mock
private InstallSourceInfo mInstallSourceInfo;
@Mock
private AppInfoDashboardFragment mFragment;
@Mock
private Preference mPreference;
@@ -74,7 +77,8 @@ public class AppInstallerInfoPreferenceControllerTest {
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
final String installerPackage = "Installer1";
when(mPackageManager.getInstallerPackageName(anyString())).thenReturn(installerPackage);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
when(mInstallSourceInfo.getInstallingPackageName()).thenReturn(installerPackage);
when(mPackageManager.getApplicationInfo(eq(installerPackage), anyInt()))
.thenReturn(mAppInfo);
mController = new AppInstallerInfoPreferenceController(mContext, "test_key");

View File

@@ -33,6 +33,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -87,7 +88,7 @@ public class InstantAppButtonsPreferenceControllerTest {
private InstantAppButtonsPreferenceController mController;
@Before
public void setUp() {
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
@@ -107,6 +108,10 @@ public class InstantAppButtonsPreferenceControllerTest {
when(mPreference.getKey()).thenReturn("instant_app_buttons");
mScreen.addPreference(mPreference);
when(mPreference.findViewById(R.id.instant_app_button_container)).thenReturn(buttons);
final InstallSourceInfo installSourceInfo = mock(InstallSourceInfo.class);
when(mPackageManager.getInstallSourceInfo(TEST_AIA_PACKAGE_NAME))
.thenReturn(installSourceInfo);
when(installSourceInfo.getInstallingPackageName()).thenReturn(TEST_INSTALLER_PACKAGE_NAME);
}
@Test
@@ -165,12 +170,7 @@ public class InstantAppButtonsPreferenceControllerTest {
@Test
public void onPrepareOptionsMenu_hasAppStoreLink_shoulNotDisableInstallInstantAppMenu() {
ReflectionHelpers.setField(mController, "mLaunchUri", "www.test.launch");
final ResolveInfo resolveInfo = mock(ResolveInfo.class);
final ActivityInfo activityInfo = mock(ActivityInfo.class);
resolveInfo.activityInfo = activityInfo;
activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
initAppStoreInfo();
final Menu menu = mock(Menu.class);
final MenuItem menuItem = mock(MenuItem.class);
when(menu.findItem(AppInfoDashboardFragment.INSTALL_INSTANT_APP_MENU)).thenReturn(menuItem);
@@ -191,12 +191,7 @@ public class InstantAppButtonsPreferenceControllerTest {
@Test
public void onOptionsItemSelected_shouldOpenAppStore() {
final ResolveInfo resolveInfo = mock(ResolveInfo.class);
final ActivityInfo activityInfo = mock(ActivityInfo.class);
resolveInfo.activityInfo = activityInfo;
activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
initAppStoreInfo();
mController.displayPreference(mScreen);
final ComponentName componentName =
new ComponentName(TEST_INSTALLER_PACKAGE_NAME, TEST_INSTALLER_ACTIVITY_NAME);
@@ -235,12 +230,7 @@ public class InstantAppButtonsPreferenceControllerTest {
@Test
public void displayPreference_hasAppStoreLink_shoulSetClickListenerForInstallButton() {
final ResolveInfo resolveInfo = mock(ResolveInfo.class);
final ActivityInfo activityInfo = mock(ActivityInfo.class);
resolveInfo.activityInfo = activityInfo;
activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
initAppStoreInfo();
mController.displayPreference(mScreen);
@@ -272,12 +262,7 @@ public class InstantAppButtonsPreferenceControllerTest {
@Test
public void clickInstallButton_shouldOpenAppStore() {
final ResolveInfo resolveInfo = mock(ResolveInfo.class);
final ActivityInfo activityInfo = mock(ActivityInfo.class);
resolveInfo.activityInfo = activityInfo;
activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
initAppStoreInfo();
mController.displayPreference(mScreen);
final ComponentName componentName =
new ComponentName(TEST_INSTALLER_PACKAGE_NAME, TEST_INSTALLER_ACTIVITY_NAME);
@@ -302,4 +287,13 @@ public class InstantAppButtonsPreferenceControllerTest {
verify(fragmentTransaction).add(any(InstantAppButtonDialogFragment.class),
eq("instant_app_buttons"));
}
private void initAppStoreInfo() {
final ResolveInfo resolveInfo = mock(ResolveInfo.class);
final ActivityInfo activityInfo = mock(ActivityInfo.class);
resolveInfo.activityInfo = activityInfo;
activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME;
activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME;
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
}
}