blob: 9f2d821cc147e77314c7b474c5e8d85975877b81 [file] [log] [blame]
/*
* Copyright (C) 2019 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.appenumeration.cts;
import static android.Manifest.permission.SET_PREFERRED_APPLICATIONS;
import static android.appenumeration.cts.Constants.ACTION_AWAIT_LAUNCHER_APPS_CALLBACK;
import static android.appenumeration.cts.Constants.ACTION_AWAIT_LAUNCHER_APPS_SESSION_CALLBACK;
import static android.appenumeration.cts.Constants.ACTION_BIND_SERVICE;
import static android.appenumeration.cts.Constants.ACTION_CAN_PACKAGE_QUERY;
import static android.appenumeration.cts.Constants.ACTION_CHECK_PACKAGE;
import static android.appenumeration.cts.Constants.ACTION_CHECK_SIGNATURES;
import static android.appenumeration.cts.Constants.ACTION_CHECK_URI_PERMISSION;
import static android.appenumeration.cts.Constants.ACTION_GET_ALL_PACKAGE_INSTALLER_SESSIONS;
import static android.appenumeration.cts.Constants.ACTION_GET_ALL_SESSIONS;
import static android.appenumeration.cts.Constants.ACTION_GET_INSTALLED_ACCESSIBILITYSERVICES_PACKAGES;
import static android.appenumeration.cts.Constants.ACTION_GET_INSTALLED_APPWIDGET_PROVIDERS;
import static android.appenumeration.cts.Constants.ACTION_GET_INSTALLED_PACKAGES;
import static android.appenumeration.cts.Constants.ACTION_GET_NAMES_FOR_UIDS;
import static android.appenumeration.cts.Constants.ACTION_GET_NAME_FOR_UID;
import static android.appenumeration.cts.Constants.ACTION_GET_PACKAGES_FOR_UID;
import static android.appenumeration.cts.Constants.ACTION_GET_PACKAGE_INFO;
import static android.appenumeration.cts.Constants.ACTION_GET_PREFERRED_ACTIVITIES;
import static android.appenumeration.cts.Constants.ACTION_GET_SESSION_INFO;
import static android.appenumeration.cts.Constants.ACTION_GET_SHAREDLIBRARY_DEPENDENT_PACKAGES;
import static android.appenumeration.cts.Constants.ACTION_GET_STAGED_SESSIONS;
import static android.appenumeration.cts.Constants.ACTION_GET_SYNCADAPTER_PACKAGES_FOR_AUTHORITY;
import static android.appenumeration.cts.Constants.ACTION_GET_SYNCADAPTER_TYPES;
import static android.appenumeration.cts.Constants.ACTION_GRANT_URI_PERMISSION;
import static android.appenumeration.cts.Constants.ACTION_HAS_SIGNING_CERTIFICATE;
import static android.appenumeration.cts.Constants.ACTION_JUST_FINISH;
import static android.appenumeration.cts.Constants.ACTION_LAUNCHER_APPS_GET_SUSPENDED_PACKAGE_LAUNCHER_EXTRAS;
import static android.appenumeration.cts.Constants.ACTION_LAUNCHER_APPS_IS_ACTIVITY_ENABLED;
import static android.appenumeration.cts.Constants.ACTION_LAUNCHER_APPS_SHOULD_HIDE_FROM_SUGGESTIONS;
import static android.appenumeration.cts.Constants.ACTION_MANIFEST_ACTIVITY;
import static android.appenumeration.cts.Constants.ACTION_MANIFEST_PROVIDER;
import static android.appenumeration.cts.Constants.ACTION_MANIFEST_SERVICE;
import static android.appenumeration.cts.Constants.ACTION_PENDING_INTENT_GET_ACTIVITY;
import static android.appenumeration.cts.Constants.ACTION_PENDING_INTENT_GET_CREATOR_PACKAGE;
import static android.appenumeration.cts.Constants.ACTION_QUERY_ACTIVITIES;
import static android.appenumeration.cts.Constants.ACTION_QUERY_PROVIDERS;
import static android.appenumeration.cts.Constants.ACTION_QUERY_RESOLVER;
import static android.appenumeration.cts.Constants.ACTION_QUERY_SERVICES;
import static android.appenumeration.cts.Constants.ACTION_REQUEST_SYNC_AND_AWAIT_STATUS;
import static android.appenumeration.cts.Constants.ACTION_REVOKE_URI_PERMISSION;
import static android.appenumeration.cts.Constants.ACTION_SET_INSTALLER_PACKAGE_NAME;
import static android.appenumeration.cts.Constants.ACTION_START_DIRECTLY;
import static android.appenumeration.cts.Constants.ACTION_START_FOR_RESULT;
import static android.appenumeration.cts.Constants.ACTION_TAKE_PERSISTABLE_URI_PERMISSION;
import static android.appenumeration.cts.Constants.ACTIVITY_CLASS_DUMMY_ACTIVITY;
import static android.appenumeration.cts.Constants.ACTIVITY_CLASS_TEST;
import static android.appenumeration.cts.Constants.CALLBACK_EVENT_INVALID;
import static android.appenumeration.cts.Constants.CALLBACK_EVENT_PACKAGES_SUSPENDED;
import static android.appenumeration.cts.Constants.CALLBACK_EVENT_PACKAGES_UNSUSPENDED;
import static android.appenumeration.cts.Constants.CALLBACK_EVENT_PACKAGE_ADDED;
import static android.appenumeration.cts.Constants.CALLBACK_EVENT_PACKAGE_CHANGED;
import static android.appenumeration.cts.Constants.CALLBACK_EVENT_PACKAGE_REMOVED;
import static android.appenumeration.cts.Constants.EXTRA_ACCOUNT;
import static android.appenumeration.cts.Constants.EXTRA_AUTHORITY;
import static android.appenumeration.cts.Constants.EXTRA_CERT;
import static android.appenumeration.cts.Constants.EXTRA_DATA;
import static android.appenumeration.cts.Constants.EXTRA_ERROR;
import static android.appenumeration.cts.Constants.EXTRA_FLAGS;
import static android.appenumeration.cts.Constants.EXTRA_ID;
import static android.appenumeration.cts.Constants.EXTRA_PENDING_INTENT;
import static android.appenumeration.cts.Constants.EXTRA_REMOTE_CALLBACK;
import static android.appenumeration.cts.Constants.EXTRA_REMOTE_READY_CALLBACK;
import static android.appenumeration.cts.Constants.QUERIES_ACTIVITY_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_PERM;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_PROVIDER;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_Q;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_RECEIVES_NON_PERSISTABLE_URI;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_RECEIVES_NON_PERSISTABLE_URI_APK;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_RECEIVES_PERM_URI;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_RECEIVES_PERSISTABLE_URI;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_RECEIVES_PERSISTABLE_URI_APK;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_RECEIVES_URI;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_SEES_INSTALLER;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_SEES_INSTALLER_APK;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_SHARED_USER;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_USES_LIBRARY;
import static android.appenumeration.cts.Constants.QUERIES_NOTHING_USES_OPTIONAL_LIBRARY;
import static android.appenumeration.cts.Constants.QUERIES_PACKAGE;
import static android.appenumeration.cts.Constants.QUERIES_PACKAGE_PROVIDER;
import static android.appenumeration.cts.Constants.QUERIES_PROVIDER_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_PROVIDER_AUTH;
import static android.appenumeration.cts.Constants.QUERIES_SERVICE_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_UNEXPORTED_ACTIVITY_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_UNEXPORTED_PROVIDER_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_UNEXPORTED_PROVIDER_AUTH;
import static android.appenumeration.cts.Constants.QUERIES_UNEXPORTED_SERVICE_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_ACTION;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_BROWSABLE;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_BROWSER;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_CONTACTS;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_EDITOR;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_SHARE;
import static android.appenumeration.cts.Constants.QUERIES_WILDCARD_WEB;
import static android.appenumeration.cts.Constants.TARGET_APPWIDGETPROVIDER;
import static android.appenumeration.cts.Constants.TARGET_APPWIDGETPROVIDER_SHARED_USER;
import static android.appenumeration.cts.Constants.TARGET_BROWSER;
import static android.appenumeration.cts.Constants.TARGET_BROWSER_WILDCARD;
import static android.appenumeration.cts.Constants.TARGET_CONTACTS;
import static android.appenumeration.cts.Constants.TARGET_EDITOR;
import static android.appenumeration.cts.Constants.TARGET_FILTERS;
import static android.appenumeration.cts.Constants.TARGET_FILTERS_APK;
import static android.appenumeration.cts.Constants.TARGET_FORCEQUERYABLE;
import static android.appenumeration.cts.Constants.TARGET_FORCEQUERYABLE_NORMAL;
import static android.appenumeration.cts.Constants.TARGET_NO_API;
import static android.appenumeration.cts.Constants.TARGET_PREFERRED_ACTIVITY;
import static android.appenumeration.cts.Constants.TARGET_PREFIX_WILDCARD_WEB;
import static android.appenumeration.cts.Constants.TARGET_SHARE;
import static android.appenumeration.cts.Constants.TARGET_SHARED_LIBRARY_PACKAGE;
import static android.appenumeration.cts.Constants.TARGET_SHARED_USER;
import static android.appenumeration.cts.Constants.TARGET_STUB;
import static android.appenumeration.cts.Constants.TARGET_STUB_APK;
import static android.appenumeration.cts.Constants.TARGET_SYNCADAPTER;
import static android.appenumeration.cts.Constants.TARGET_SYNCADAPTER_SHARED_USER;
import static android.appenumeration.cts.Constants.TARGET_WEB;
import static android.content.Intent.EXTRA_PACKAGES;
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
import static android.content.pm.PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
import static android.os.Process.INVALID_UID;
import static android.os.Process.ROOT_UID;
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyArray;
import static org.hamcrest.Matchers.emptyOrNullString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasItemInArray;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SyncAdapterType;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteCallback;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AmUtils;
import com.android.compatibility.common.util.SystemUtil;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
import com.android.cts.install.lib.LocalIntentSender;
import com.android.cts.install.lib.TestApp;
import org.hamcrest.core.IsNull;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidJUnit4.class)
public class AppEnumerationTests {
private static Handler sResponseHandler;
private static HandlerThread sResponseThread;
private static boolean sGlobalFeatureEnabled;
private static PackageManager sPm;
private static AccountManager sAccountManager;
// The shared library for getting dependent packages
private static final String TEST_SHARED_LIB_NAME = "android.test.runner";
private static final String TEST_NONEXISTENT_PACKAGE_NAME_1 = "com.android.cts.nonexistent1";
private static final String TEST_NONEXISTENT_PACKAGE_NAME_2 = "com.android.cts.nonexistent2";
private static final Account ACCOUNT_SYNCADAPTER = new Account(
TARGET_SYNCADAPTER, "android.appenumeration.account.type");
private static final Account ACCOUNT_SYNCADAPTER_SHARED_USER = new Account(
TARGET_SYNCADAPTER_SHARED_USER, "android.appenumeration.shareduid.account.type");
@Rule
public TestName name = new TestName();
@BeforeClass
public static void setup() {
final String deviceConfigResponse =
SystemUtil.runShellCommand(
"device_config get package_manager_service "
+ "package_query_filtering_enabled")
.trim();
if ("null".equalsIgnoreCase(deviceConfigResponse) || deviceConfigResponse.isEmpty()) {
sGlobalFeatureEnabled = true;
} else {
sGlobalFeatureEnabled = Boolean.parseBoolean(deviceConfigResponse);
}
System.out.println("Feature enabled: " + sGlobalFeatureEnabled);
if (!sGlobalFeatureEnabled) return;
sResponseThread = new HandlerThread("response");
sResponseThread.start();
sResponseHandler = new Handler(sResponseThread.getLooper());
sPm = InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
sAccountManager = AccountManager.get(
InstrumentationRegistry.getInstrumentation().getContext());
assertThat(sAccountManager.addAccountExplicitly(ACCOUNT_SYNCADAPTER,
null /* password */, null /* userdata */), is(true));
assertThat(sAccountManager.addAccountExplicitly(ACCOUNT_SYNCADAPTER_SHARED_USER,
null /* password */, null /* userdata */), is(true));
}
@AfterClass
public static void tearDown() {
if (!sGlobalFeatureEnabled) return;
sResponseThread.quit();
assertThat(sAccountManager.removeAccountExplicitly(ACCOUNT_SYNCADAPTER),
is(true));
assertThat(sAccountManager.removeAccountExplicitly(ACCOUNT_SYNCADAPTER_SHARED_USER),
is(true));
}
@Test
public void systemPackagesQueryable_notEnabled() throws Exception {
final Resources resources = Resources.getSystem();
assertFalse(
"config_forceSystemPackagesQueryable must not be true.",
resources.getBoolean(resources.getIdentifier(
"config_forceSystemPackagesQueryable", "bool", "android")));
// now let's assert that that the actual set of system apps is limited
assertThat("Not all system apps should be visible.",
getInstalledPackages(QUERIES_NOTHING_PERM, MATCH_SYSTEM_ONLY).length,
greaterThan(getInstalledPackages(QUERIES_NOTHING, MATCH_SYSTEM_ONLY).length));
}
@Test
public void all_canSeeForceQueryable() throws Exception {
assertVisible(QUERIES_NOTHING, TARGET_FORCEQUERYABLE);
assertVisible(QUERIES_ACTIVITY_ACTION, TARGET_FORCEQUERYABLE);
assertVisible(QUERIES_SERVICE_ACTION, TARGET_FORCEQUERYABLE);
assertVisible(QUERIES_PROVIDER_AUTH, TARGET_FORCEQUERYABLE);
assertVisible(QUERIES_PACKAGE, TARGET_FORCEQUERYABLE);
}
@Test
public void all_cannotSeeForceQueryableInstalledNormally() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_FORCEQUERYABLE_NORMAL);
assertNotVisible(QUERIES_ACTIVITY_ACTION, TARGET_FORCEQUERYABLE_NORMAL);
assertNotVisible(QUERIES_SERVICE_ACTION, TARGET_FORCEQUERYABLE_NORMAL);
assertNotVisible(QUERIES_PROVIDER_AUTH, TARGET_FORCEQUERYABLE_NORMAL);
assertNotVisible(QUERIES_PACKAGE, TARGET_FORCEQUERYABLE_NORMAL);
}
@Test
public void startExplicitly_canStartNonVisible() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_FILTERS);
startExplicitIntentViaComponent(QUERIES_NOTHING, TARGET_FILTERS);
startExplicitIntentViaPackageName(QUERIES_NOTHING, TARGET_FILTERS);
}
@Test
public void startExplicitly_canStartVisible() throws Exception {
assertVisible(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS);
startExplicitIntentViaComponent(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS);
startExplicitIntentViaPackageName(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS);
}
@Test
public void startImplicitly_canStartNonVisible() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_FILTERS);
startImplicitIntent(QUERIES_NOTHING);
}
@Test
public void startActivityWithNoPermissionUri_canSeeProvider() throws Exception {
assertNotVisible(QUERIES_NOTHING_RECEIVES_URI, QUERIES_NOTHING_PERM);
// send with uri but no grant flags; shouldn't be visible
startExplicitActivityWithIntent(QUERIES_NOTHING_PERM, QUERIES_NOTHING_RECEIVES_URI,
new Intent(ACTION_JUST_FINISH)
.setData(Uri.parse("content://" + QUERIES_NOTHING_PERM + "/test")));
assertNotVisible(QUERIES_NOTHING_RECEIVES_URI, QUERIES_NOTHING_PERM);
// send again with uri bug grant flags now set; should be visible
startExplicitActivityWithIntent(QUERIES_NOTHING_PERM, QUERIES_NOTHING_RECEIVES_URI,
new Intent(ACTION_JUST_FINISH)
.setData(Uri.parse("content://" + QUERIES_NOTHING_PERM + "/test"))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION));
assertVisible(QUERIES_NOTHING_RECEIVES_URI, QUERIES_NOTHING_PERM);
}
@Test
public void startActivityWithUri_canSeePermissionProtectedProvider() throws Exception {
assertNotVisible(QUERIES_NOTHING_RECEIVES_PERM_URI, QUERIES_NOTHING_PERM);
// send with uri but no grant flags; shouldn't be visible
startExplicitActivityWithIntent(QUERIES_NOTHING_PERM, QUERIES_NOTHING_RECEIVES_PERM_URI,
new Intent(ACTION_JUST_FINISH)
.setData(Uri.parse("content://" + QUERIES_NOTHING_PERM + "2/test")));
assertNotVisible(QUERIES_NOTHING_RECEIVES_PERM_URI, QUERIES_NOTHING_PERM);
// send again with uri bug grant flags now set; should be visible
startExplicitActivityWithIntent(QUERIES_NOTHING_PERM, QUERIES_NOTHING_RECEIVES_PERM_URI,
new Intent(ACTION_JUST_FINISH)
.setData(Uri.parse("content://" + QUERIES_NOTHING_PERM + "2/test"))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION));
assertVisible(QUERIES_NOTHING_RECEIVES_PERM_URI, QUERIES_NOTHING_PERM);
}
@Test
public void startActivityWithUriGrant_cannotSeeProviderAfterUpdated() throws Exception {
assertNotVisible(QUERIES_NOTHING_RECEIVES_NON_PERSISTABLE_URI, QUERIES_NOTHING_PERM);
// send with uri grant flags; should be visible
startExplicitActivityWithIntent(QUERIES_NOTHING_PERM,
QUERIES_NOTHING_RECEIVES_NON_PERSISTABLE_URI,
new Intent(ACTION_JUST_FINISH)
.setData(Uri.parse("content://" + QUERIES_NOTHING_PERM + "3/test"))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION));
assertVisible(QUERIES_NOTHING_RECEIVES_NON_PERSISTABLE_URI, QUERIES_NOTHING_PERM);
// update the package; shouldn't be visible
runShellCommand("pm install " + QUERIES_NOTHING_RECEIVES_NON_PERSISTABLE_URI_APK);
// Wait until the updating is done
AmUtils.waitForBroadcastIdle();
assertNotVisible(QUERIES_NOTHING_RECEIVES_NON_PERSISTABLE_URI, QUERIES_NOTHING_PERM);
}
@Test
public void startActivityWithPersistableUriGrant_canSeeProviderAfterUpdated() throws Exception {
assertNotVisible(QUERIES_NOTHING_RECEIVES_PERSISTABLE_URI, QUERIES_NOTHING_PERM);
// send with persistable uri grant flags; should be visible
startExplicitActivityWithIntent(QUERIES_NOTHING_PERM,
QUERIES_NOTHING_RECEIVES_PERSISTABLE_URI,
new Intent(ACTION_TAKE_PERSISTABLE_URI_PERMISSION)
.setData(Uri.parse("content://" + QUERIES_NOTHING_PERM + "3/test"))
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
assertVisible(QUERIES_NOTHING_RECEIVES_PERSISTABLE_URI, QUERIES_NOTHING_PERM);
// update the package; should be still visible
runShellCommand("pm install " + QUERIES_NOTHING_RECEIVES_PERSISTABLE_URI_APK);
// Wait until the updating is done
AmUtils.waitForBroadcastIdle();
assertVisible(QUERIES_NOTHING_RECEIVES_PERSISTABLE_URI, QUERIES_NOTHING_PERM);
}
private void startExplicitActivityWithIntent(
String sourcePackageName, String targetPackageName, Intent intent) throws Exception {
sendCommandBlocking(sourcePackageName, targetPackageName,
intent.setClassName(targetPackageName, ACTIVITY_CLASS_TEST),
ACTION_START_DIRECTLY);
}
@Test
public void queriesNothing_cannotSeeNonForceQueryable() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_NO_API);
assertNotVisible(QUERIES_NOTHING, TARGET_FILTERS);
}
@Test
public void queriesNothingTargetsQ_canSeeAll() throws Exception {
assertVisible(QUERIES_NOTHING_Q, TARGET_FORCEQUERYABLE);
assertVisible(QUERIES_NOTHING_Q, TARGET_NO_API);
assertVisible(QUERIES_NOTHING_Q, TARGET_FILTERS);
}
@Test
public void queriesNothingHasPermission_canSeeAll() throws Exception {
assertVisible(QUERIES_NOTHING_PERM, TARGET_FORCEQUERYABLE);
assertVisible(QUERIES_NOTHING_PERM, TARGET_NO_API);
assertVisible(QUERIES_NOTHING_PERM, TARGET_FILTERS);
}
@Test
public void queriesNothing_cannotSeeFilters() throws Exception {
assertNotQueryable(QUERIES_NOTHING, TARGET_FILTERS,
ACTION_MANIFEST_ACTIVITY, this::queryIntentActivities);
assertNotQueryable(QUERIES_NOTHING, TARGET_FILTERS,
ACTION_MANIFEST_SERVICE, this::queryIntentServices);
assertNotQueryable(QUERIES_NOTHING, TARGET_FILTERS,
ACTION_MANIFEST_PROVIDER, this::queryIntentProviders);
}
@Test
public void queriesActivityAction_canSeeFilters() throws Exception {
assertQueryable(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS,
ACTION_MANIFEST_ACTIVITY, this::queryIntentActivities);
assertQueryable(QUERIES_SERVICE_ACTION, TARGET_FILTERS,
ACTION_MANIFEST_SERVICE, this::queryIntentServices);
assertQueryable(QUERIES_PROVIDER_AUTH, TARGET_FILTERS,
ACTION_MANIFEST_PROVIDER, this::queryIntentProviders);
assertQueryable(QUERIES_PROVIDER_ACTION, TARGET_FILTERS,
ACTION_MANIFEST_PROVIDER, this::queryIntentProviders);
}
@Test
public void queriesNothingHasPermission_canSeeFilters() throws Exception {
assertQueryable(QUERIES_NOTHING_PERM, TARGET_FILTERS,
ACTION_MANIFEST_ACTIVITY, this::queryIntentActivities);
assertQueryable(QUERIES_NOTHING_PERM, TARGET_FILTERS,
ACTION_MANIFEST_SERVICE, this::queryIntentServices);
assertQueryable(QUERIES_NOTHING_PERM, TARGET_FILTERS,
ACTION_MANIFEST_PROVIDER, this::queryIntentProviders);
}
@Test
public void queriesSomething_cannotSeeNoApi() throws Exception {
assertNotVisible(QUERIES_ACTIVITY_ACTION, TARGET_NO_API);
assertNotVisible(QUERIES_SERVICE_ACTION, TARGET_NO_API);
assertNotVisible(QUERIES_PROVIDER_AUTH, TARGET_NO_API);
assertNotVisible(QUERIES_PROVIDER_ACTION, TARGET_NO_API);
}
@Test
public void queriesActivityAction_canSeeTarget() throws Exception {
assertVisible(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS);
}
@Test
public void queriesServiceAction_canSeeTarget() throws Exception {
assertVisible(QUERIES_SERVICE_ACTION, TARGET_FILTERS);
}
@Test
public void queriesWildcardAction_canSeeTargets() throws Exception {
assertVisible(QUERIES_WILDCARD_ACTION, TARGET_FILTERS);
}
@Test
public void queriesProviderAuthority_canSeeTarget() throws Exception {
assertVisible(QUERIES_PROVIDER_AUTH, TARGET_FILTERS);
}
@Test
public void queriesProviderAction_canSeeTarget() throws Exception {
assertVisible(QUERIES_PROVIDER_ACTION, TARGET_FILTERS);
}
@Test
public void queriesActivityAction_cannotSeeUnexportedTarget() throws Exception {
assertNotVisible(QUERIES_UNEXPORTED_ACTIVITY_ACTION, TARGET_FILTERS);
}
@Test
public void queriesServiceAction_cannotSeeUnexportedTarget() throws Exception {
assertNotVisible(QUERIES_UNEXPORTED_SERVICE_ACTION, TARGET_FILTERS);
}
@Test
public void queriesProviderAuthority_cannotSeeUnexportedTarget() throws Exception {
assertNotVisible(QUERIES_UNEXPORTED_PROVIDER_AUTH, TARGET_FILTERS);
}
@Test
public void queriesProviderAction_cannotSeeUnexportedTarget() throws Exception {
assertNotVisible(QUERIES_UNEXPORTED_PROVIDER_ACTION, TARGET_FILTERS);
}
@Test
public void queriesPackage_canSeeTarget() throws Exception {
assertVisible(QUERIES_PACKAGE, TARGET_NO_API);
}
@Test
public void queriesNothing_canSeeInstaller() throws Exception {
runShellCommand("pm uninstall " + QUERIES_NOTHING_SEES_INSTALLER);
runShellCommand("pm install"
+ " -i " + TARGET_NO_API
+ " --pkg " + QUERIES_NOTHING_SEES_INSTALLER
+ " " + QUERIES_NOTHING_SEES_INSTALLER_APK);
try {
assertVisible(QUERIES_NOTHING_SEES_INSTALLER, TARGET_NO_API);
} finally {
runShellCommand("pm uninstall " + QUERIES_NOTHING_SEES_INSTALLER);
}
}
@Test
public void whenStarted_canSeeCaller() throws Exception {
// let's first make sure that the target cannot see the caller.
assertNotVisible(QUERIES_NOTHING, QUERIES_NOTHING_PERM);
// now let's start the target and make sure that it can see the caller as part of that call
PackageInfo packageInfo = startForResult(QUERIES_NOTHING_PERM, QUERIES_NOTHING);
assertThat(packageInfo, IsNull.notNullValue());
assertThat(packageInfo.packageName, is(QUERIES_NOTHING_PERM));
// and finally let's re-run the last check to make sure that the target can still see the
// caller
assertVisible(QUERIES_NOTHING, QUERIES_NOTHING_PERM);
}
@Test
public void whenStartedViaIntentSender_canSeeCaller() throws Exception {
// let's first make sure that the target cannot see the caller.
assertNotVisible(QUERIES_NOTHING, QUERIES_NOTHING_Q);
// now let's start the target via pending intent and make sure that it can see the caller
// as part of that call
PackageInfo packageInfo = startSenderForResult(QUERIES_NOTHING_Q, QUERIES_NOTHING);
assertThat(packageInfo, IsNull.notNullValue());
assertThat(packageInfo.packageName, is(QUERIES_NOTHING_Q));
// and finally let's re-run the last check to make sure that the target can still see the
// caller
assertVisible(QUERIES_NOTHING, QUERIES_NOTHING_Q);
}
@Test
public void queriesNothing_cannotSeeLibraryPackage() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_SHARED_LIBRARY_PACKAGE);
}
@Test
public void queriesNothingUsesLibrary_canSeeLibraryPackage() throws Exception {
assertVisible(QUERIES_NOTHING_USES_LIBRARY, TARGET_SHARED_LIBRARY_PACKAGE);
}
@Test
public void queriesNothing_cannotSeeOptionalLibraryPackage() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_SHARED_LIBRARY_PACKAGE);
}
@Test
public void queriesNothingUsesOptionalLibrary_canSeeLibraryPackage() throws Exception {
assertVisible(QUERIES_NOTHING_USES_OPTIONAL_LIBRARY, TARGET_SHARED_LIBRARY_PACKAGE);
}
@Test
public void queriesNothing_getPackagesForUid_consistentVisibility()
throws Exception {
final int targetSharedUid = sPm.getPackageUid(TARGET_SHARED_USER, /* flags */ 0);
final int targetUid = sPm.getPackageUid(TARGET_FILTERS, /* flags */ 0);
Assert.assertNull(getPackagesForUid(QUERIES_NOTHING, targetSharedUid));
Assert.assertNull(getPackagesForUid(QUERIES_NOTHING, targetUid));
}
@Test
public void queriesNothingHasPermission_getPackagesForUid_consistentVisibility()
throws Exception {
final int targetSharedUid = sPm.getPackageUid(TARGET_SHARED_USER, /* flags */ 0);
final int targetUid = sPm.getPackageUid(TARGET_FILTERS, /* flags */ 0);
Assert.assertNotNull(getPackagesForUid(QUERIES_NOTHING_PERM, targetSharedUid));
Assert.assertNotNull(getPackagesForUid(QUERIES_NOTHING_PERM, targetUid));
}
@Test
public void queriesNothing_getNameForUid_consistentVisibility()
throws Exception {
final int targetSharedUid = sPm.getPackageUid(TARGET_SHARED_USER, /* flags */ 0);
final int targetUid = sPm.getPackageUid(TARGET_FILTERS, /* flags */ 0);
Assert.assertNull(getNameForUid(QUERIES_NOTHING, targetSharedUid));
Assert.assertNull(getNameForUid(QUERIES_NOTHING, targetUid));
}
@Test
public void queriesNothingHasPermission_getNameForUid_consistentVisibility()
throws Exception {
final int targetSharedUid = sPm.getPackageUid(TARGET_SHARED_USER, /* flags */ 0);
final int targetUid = sPm.getPackageUid(TARGET_FILTERS, /* flags */ 0);
Assert.assertNotNull(getNameForUid(QUERIES_NOTHING_PERM, targetSharedUid));
Assert.assertNotNull(getNameForUid(QUERIES_NOTHING_PERM, targetUid));
}
@Test
public void queriesNothing_getNamesForUids_consistentVisibility()
throws Exception {
final int targetSharedUid = sPm.getPackageUid(TARGET_SHARED_USER, /* flags */ 0);
final int targetUid = sPm.getPackageUid(TARGET_FILTERS, /* flags */ 0);
Assert.assertNull(getNamesForUids(QUERIES_NOTHING, targetSharedUid)[0]);
Assert.assertNull(getNamesForUids(QUERIES_NOTHING, targetUid)[0]);
}
@Test
public void queriesNothingHasPermission_getNamesForUids_consistentVisibility()
throws Exception {
final int targetSharedUid = sPm.getPackageUid(TARGET_SHARED_USER, /* flags */ 0);
final int targetUid = sPm.getPackageUid(TARGET_FILTERS, /* flags */ 0);
Assert.assertNotNull(getNamesForUids(QUERIES_NOTHING_PERM, targetSharedUid)[0]);
Assert.assertNotNull(getNamesForUids(QUERIES_NOTHING_PERM, targetUid)[0]);
}
@Test
public void queriesNothing_checkSignatures_consistentVisibility()
throws Exception {
final int targetSharedUid = sPm.getPackageUid(TARGET_SHARED_USER, /* flags */ 0);
final int targetUid = sPm.getPackageUid(TARGET_FILTERS, /* flags */ 0);
Assert.assertEquals(SIGNATURE_UNKNOWN_PACKAGE,
checkSignatures(QUERIES_NOTHING, targetSharedUid));
Assert.assertEquals(SIGNATURE_UNKNOWN_PACKAGE,
checkSignatures(QUERIES_NOTHING, targetUid));
}
@Test
public void queriesNothingHasPermission_checkSignatures_consistentVisibility()
throws Exception {
final int targetSharedUid = sPm.getPackageUid(TARGET_SHARED_USER, /* flags */ 0);
final int targetUid = sPm.getPackageUid(TARGET_FILTERS, /* flags */ 0);
Assert.assertEquals(SIGNATURE_MATCH,
checkSignatures(QUERIES_NOTHING_PERM, targetSharedUid));
Assert.assertEquals(SIGNATURE_MATCH, checkSignatures(QUERIES_NOTHING_PERM, targetUid));
}
@Test
public void queriesNothing_hasSigningCertificate_consistentVisibility() throws Exception {
final PackageInfo targetSharedUidInfo = sPm.getPackageInfo(TARGET_SHARED_USER,
GET_SIGNING_CERTIFICATES);
final PackageInfo targetUidInfo = sPm.getPackageInfo(TARGET_FILTERS,
GET_SIGNING_CERTIFICATES);
final byte[] targetSharedCert = convertSignaturesToCertificates(
targetSharedUidInfo.signingInfo.getApkContentsSigners()).get(0).getEncoded();
final byte[] targetCert = convertSignaturesToCertificates(
targetUidInfo.signingInfo.getApkContentsSigners()).get(0).getEncoded();
Assert.assertFalse(
hasSigningCertificate(QUERIES_NOTHING, targetSharedUidInfo.applicationInfo.uid,
targetSharedCert));
Assert.assertFalse(
hasSigningCertificate(QUERIES_NOTHING, targetUidInfo.applicationInfo.uid,
targetCert));
}
@Test
public void queriesNothingHasPermission_hasSigningCertificate_consistentVisibility()
throws Exception {
final PackageInfo targetSharedUidInfo = sPm.getPackageInfo(TARGET_SHARED_USER,
GET_SIGNING_CERTIFICATES);
final PackageInfo targetUidInfo = sPm.getPackageInfo(TARGET_FILTERS,
GET_SIGNING_CERTIFICATES);
final byte[] targetSharedCert = convertSignaturesToCertificates(
targetSharedUidInfo.signingInfo.getApkContentsSigners()).get(0).getEncoded();
final byte[] targetCert = convertSignaturesToCertificates(
targetUidInfo.signingInfo.getApkContentsSigners()).get(0).getEncoded();
Assert.assertTrue(
hasSigningCertificate(QUERIES_NOTHING_PERM, targetSharedUidInfo.applicationInfo.uid,
targetSharedCert));
Assert.assertTrue(
hasSigningCertificate(QUERIES_NOTHING_PERM, targetUidInfo.applicationInfo.uid,
targetCert));
}
@Test
public void sharedUserMember_canSeeOtherMember() throws Exception {
assertVisible(QUERIES_NOTHING_SHARED_USER, TARGET_SHARED_USER);
}
@Test
public void queriesPackage_canSeeAllSharedUserMembers() throws Exception {
// explicitly queries target via manifest
assertVisible(QUERIES_PACKAGE, TARGET_SHARED_USER);
// implicitly granted visibility to other member of shared user
assertVisible(QUERIES_PACKAGE, QUERIES_NOTHING_SHARED_USER);
}
@Test
public void queriesWildcardContacts() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_CONTACTS);
assertVisible(QUERIES_WILDCARD_CONTACTS, TARGET_CONTACTS);
}
@Test
public void queriesWildcardWeb() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_WEB);
assertVisible(QUERIES_WILDCARD_BROWSABLE, TARGET_WEB);
assertVisible(QUERIES_WILDCARD_WEB, TARGET_WEB);
}
@Test
public void queriesWildcardBrowser() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_BROWSER);
assertNotVisible(QUERIES_WILDCARD_BROWSER, TARGET_WEB);
assertVisible(QUERIES_WILDCARD_BROWSER, TARGET_BROWSER);
assertVisible(QUERIES_WILDCARD_BROWSER, TARGET_BROWSER_WILDCARD);
}
@Test
public void queriesWildcardWeb_canSeePrefixWildcardWeb() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_PREFIX_WILDCARD_WEB);
assertVisible(QUERIES_WILDCARD_BROWSABLE, TARGET_PREFIX_WILDCARD_WEB);
assertVisible(QUERIES_WILDCARD_WEB, TARGET_PREFIX_WILDCARD_WEB);
}
@Test
public void queriesWildcardBrowser_cannotseePrefixWildcardWeb() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_PREFIX_WILDCARD_WEB);
assertNotVisible(QUERIES_WILDCARD_BROWSER, TARGET_PREFIX_WILDCARD_WEB);
}
@Test
public void queriesWildcardEditor() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_EDITOR);
assertVisible(QUERIES_WILDCARD_EDITOR, TARGET_EDITOR);
}
@Test
public void queriesWildcardShareSheet() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_SHARE);
assertVisible(QUERIES_WILDCARD_SHARE, TARGET_SHARE);
}
@Test
public void queriesNothing_cannotSeeA11yService() throws Exception {
if (!sGlobalFeatureEnabled) return;
final String[] result = getInstalledAccessibilityServices(QUERIES_NOTHING);
assertThat(result, not(hasItemInArray(TARGET_FILTERS)));
}
@Test
public void queriesNothingHasPermission_canSeeA11yService() throws Exception {
if (!sGlobalFeatureEnabled) return;
final String[] result = getInstalledAccessibilityServices(QUERIES_NOTHING_PERM);
assertThat(QUERIES_NOTHING_PERM + " should be able to see " + TARGET_FILTERS,
result, hasItemInArray(TARGET_FILTERS));
}
private void assertVisible(String sourcePackageName, String targetPackageName)
throws Exception {
if (!sGlobalFeatureEnabled) return;
Assert.assertNotNull(sourcePackageName + " should be able to see " + targetPackageName,
getPackageInfo(sourcePackageName, targetPackageName));
}
@Test
public void broadcastAdded_notVisibleDoesNotReceive() throws Exception {
final Result result = sendCommand(QUERIES_NOTHING, TARGET_FILTERS,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_ADDED, /* waitForReady */ true);
runShellCommand("pm install " + TARGET_FILTERS_APK);
try {
result.await();
fail();
} catch (MissingBroadcastException e) {
// hooray
}
}
@Test
public void broadcastAdded_visibleReceives() throws Exception {
final Result result = sendCommand(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_ADDED, /* waitForReady */ true);
runShellCommand("pm install " + TARGET_FILTERS_APK);
try {
Assert.assertEquals(TARGET_FILTERS,
Uri.parse(result.await().getString(EXTRA_DATA)).getSchemeSpecificPart());
} catch (MissingBroadcastException e) {
fail();
}
}
@Test
public void reinstallTarget_broadcastRemoved_notVisibleDoesNotReceive() throws Exception {
final Result result = sendCommand(QUERIES_NOTHING, TARGET_FILTERS,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_REMOVED, /* waitForReady */ true);
runShellCommand("pm install " + TARGET_FILTERS_APK);
try {
result.await();
fail();
} catch (MissingBroadcastException e) {
// hooray
}
}
@Test
public void reinstallTarget_broadcastRemoved_visibleReceives() throws Exception {
final Result result = sendCommand(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_REMOVED, /* waitForReady */ true);
runShellCommand("pm install " + TARGET_FILTERS_APK);
try {
Assert.assertEquals(TARGET_FILTERS,
Uri.parse(result.await().getString(EXTRA_DATA)).getSchemeSpecificPart());
} catch (MissingBroadcastException e) {
fail();
}
}
@Test
public void uninstallTarget_broadcastRemoved_notVisibleDoesNotReceive() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
final Result result = sendCommand(QUERIES_NOTHING, TARGET_STUB,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_REMOVED, /* waitForReady */ true);
runShellCommand("pm uninstall " + TARGET_STUB);
try {
result.await();
fail();
} catch (MissingBroadcastException e) {
// hooray
}
}
@Test
public void uninstallTarget_broadcastRemoved_visibleReceives() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
final Result result = sendCommand(QUERIES_NOTHING_PERM, TARGET_STUB,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_REMOVED, /* waitForReady */ true);
runShellCommand("pm uninstall " + TARGET_STUB);
try {
Assert.assertEquals(TARGET_STUB,
Uri.parse(result.await().getString(EXTRA_DATA)).getSchemeSpecificPart());
} catch (MissingBroadcastException e) {
fail();
}
}
@Test
public void uninstallTarget_broadcastFullyRemoved_notVisibleDoesNotReceive() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
final Result result = sendCommand(QUERIES_NOTHING, TARGET_STUB,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_FULLY_REMOVED, /* waitForReady */ true);
runShellCommand("pm uninstall " + TARGET_STUB);
try {
result.await();
fail();
} catch (MissingBroadcastException e) {
// hooray
}
}
@Test
public void uninstallTarget_broadcastFullyRemoved_visibleReceives() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
final Result result = sendCommand(QUERIES_NOTHING_PERM, TARGET_STUB,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_FULLY_REMOVED, /* waitForReady */ true);
runShellCommand("pm uninstall " + TARGET_STUB);
try {
Assert.assertEquals(TARGET_STUB,
Uri.parse(result.await().getString(EXTRA_DATA)).getSchemeSpecificPart());
} catch (MissingBroadcastException e) {
fail();
}
}
@Test
public void clearTargetData_broadcastDataCleared_notVisibleDoesNotReceive() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
final Result result = sendCommand(QUERIES_NOTHING, TARGET_STUB,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_DATA_CLEARED, /* waitForReady */ true);
runShellCommand("pm clear --user cur " + TARGET_STUB);
try {
result.await();
fail();
} catch (MissingBroadcastException e) {
// hooray
}
}
@Test
public void clearTargetData_broadcastDataCleared_visibleReceives() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
final Result result = sendCommand(QUERIES_NOTHING_PERM, TARGET_STUB,
/* targetUid */ INVALID_UID, /* intentExtra */ null,
Constants.ACTION_AWAIT_PACKAGE_DATA_CLEARED, /* waitForReady */ true);
runShellCommand("pm clear --user cur " + TARGET_STUB);
try {
Assert.assertEquals(TARGET_STUB,
Uri.parse(result.await().getString(EXTRA_DATA)).getSchemeSpecificPart());
} catch (MissingBroadcastException e) {
fail();
}
}
@Test
public void broadcastSuspended_visibleReceives() throws Exception {
assertBroadcastSuspendedVisible(QUERIES_PACKAGE,
Arrays.asList(TARGET_NO_API, TARGET_SYNCADAPTER),
Arrays.asList(TARGET_NO_API, TARGET_SYNCADAPTER));
}
@Test
public void broadcastSuspended_notVisibleDoesNotReceive() throws Exception {
assertBroadcastSuspendedVisible(QUERIES_NOTHING,
Arrays.asList(),
Arrays.asList(TARGET_NO_API, TARGET_SYNCADAPTER));
}
@Test
public void broadcastSuspended_visibleReceivesAndNotVisibleDoesNotReceive() throws Exception {
assertBroadcastSuspendedVisible(QUERIES_ACTIVITY_ACTION,
Arrays.asList(TARGET_FILTERS),
Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
}
@Test
public void launcherAppsCallback_added_notVisibleNotReceives() throws Exception {
ensurePackageIsNotInstalled(TARGET_STUB);
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_NOTHING,
CALLBACK_EVENT_PACKAGE_ADDED);
runShellCommand("pm install " + TARGET_STUB_APK);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_INVALID));
assertThat(response.getStringArray(EXTRA_PACKAGES), emptyArray());
}
@Test
public void launcherAppsCallback_added_visibleReceives() throws Exception {
ensurePackageIsNotInstalled(TARGET_STUB);
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_NOTHING_PERM,
CALLBACK_EVENT_PACKAGE_ADDED);
runShellCommand("pm install " + TARGET_STUB_APK);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_PACKAGE_ADDED));
assertThat(response.getStringArray(EXTRA_PACKAGES),
arrayContainingInAnyOrder(new String[]{TARGET_STUB}));
}
@Test
public void launcherAppsCallback_removed_notVisibleNotReceives() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_NOTHING,
CALLBACK_EVENT_PACKAGE_REMOVED);
runShellCommand("pm uninstall " + TARGET_STUB);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_INVALID));
assertThat(response.getStringArray(EXTRA_PACKAGES), emptyArray());
}
@Test
public void launcherAppsCallback_removed_visibleReceives() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_NOTHING_PERM,
CALLBACK_EVENT_PACKAGE_REMOVED);
runShellCommand("pm uninstall " + TARGET_STUB);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_PACKAGE_REMOVED));
assertThat(response.getStringArray(EXTRA_PACKAGES),
arrayContainingInAnyOrder(new String[]{TARGET_STUB}));
}
@Test
public void launcherAppsCallback_changed_notVisibleNotReceives() throws Exception {
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_NOTHING,
CALLBACK_EVENT_PACKAGE_CHANGED);
runShellCommand("pm install " + TARGET_FILTERS_APK);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_INVALID));
assertThat(response.getStringArray(EXTRA_PACKAGES), emptyArray());
}
@Test
public void launcherAppsCallback_changed_visibleReceives() throws Exception {
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_NOTHING_PERM,
CALLBACK_EVENT_PACKAGE_CHANGED);
runShellCommand("pm install " + TARGET_FILTERS_APK);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_PACKAGE_CHANGED));
assertThat(response.getStringArray(EXTRA_PACKAGES),
arrayContainingInAnyOrder(new String[]{TARGET_FILTERS}));
}
@Test
public void launcherAppsCallback_suspended_notVisibleNotReceives() throws Exception {
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_NOTHING,
CALLBACK_EVENT_PACKAGES_SUSPENDED);
try {
setPackagesSuspended(/* suspend */ true,
Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_INVALID));
assertThat(response.getStringArray(EXTRA_PACKAGES), emptyArray());
} finally {
setPackagesSuspended(/* suspend */ false,
Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
}
}
@Test
public void launcherAppsCallback_suspended_visibleReceives() throws Exception {
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_ACTIVITY_ACTION,
CALLBACK_EVENT_PACKAGES_SUSPENDED);
try {
setPackagesSuspended(/* suspend */ true,
Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_PACKAGES_SUSPENDED));
assertThat(response.getStringArray(EXTRA_PACKAGES),
arrayContainingInAnyOrder(new String[]{TARGET_FILTERS}));
} finally {
setPackagesSuspended(/* suspend */ false,
Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
}
}
@Test
public void launcherAppsCallback_unsuspended_notVisibleNotReceives() throws Exception {
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_NOTHING,
CALLBACK_EVENT_PACKAGES_UNSUSPENDED);
setPackagesSuspended(/* suspend */ false, Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_INVALID));
assertThat(response.getStringArray(EXTRA_PACKAGES), emptyArray());
}
@Test
public void launcherAppsCallback_unsuspended_visibleReceives() throws Exception {
final Result result = sendCommandAndWaitForLauncherAppsCallback(QUERIES_ACTIVITY_ACTION,
CALLBACK_EVENT_PACKAGES_UNSUSPENDED);
setPackagesSuspended(/* suspend */ false, Arrays.asList(TARGET_NO_API, TARGET_FILTERS));
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_FLAGS), equalTo(CALLBACK_EVENT_PACKAGES_UNSUSPENDED));
assertThat(response.getStringArray(EXTRA_PACKAGES),
arrayContainingInAnyOrder(new String[]{TARGET_FILTERS}));
}
@Test
public void launcherAppsSessionCallback_queriesNothing_cannotSeeSession() throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Result result = sendCommandAndWaitForLauncherAppsSessionCallback(
QUERIES_NOTHING, sessionId);
commitSession(sessionId);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_ID), equalTo(SessionInfo.INVALID_ID));
} finally {
runShellCommand("pm uninstall " + TestApp.A);
dropShellPermissions();
}
}
@Test
public void launcherAppsSessionCallback_queriesNothingHasPermission_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Result result = sendCommandAndWaitForLauncherAppsSessionCallback(
QUERIES_NOTHING_PERM, sessionId);
commitSession(sessionId);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_ID), equalTo(sessionId));
} finally {
runShellCommand("pm uninstall " + TestApp.A);
dropShellPermissions();
}
}
@Test
public void launcherAppsSessionCallback_queriesPackage_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Result result = sendCommandAndWaitForLauncherAppsSessionCallback(
QUERIES_PACKAGE, sessionId);
commitSession(sessionId);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_ID), equalTo(sessionId));
} finally {
runShellCommand("pm uninstall " + TestApp.A);
dropShellPermissions();
}
}
@Test
public void launcherAppsSessionCallback_queriesNothingTargetsQ_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Result result = sendCommandAndWaitForLauncherAppsSessionCallback(
QUERIES_NOTHING_Q, sessionId);
commitSession(sessionId);
final Bundle response = result.await();
assertThat(response.getInt(EXTRA_ID), equalTo(sessionId));
} finally {
runShellCommand("pm uninstall " + TestApp.A);
dropShellPermissions();
}
}
@Test
public void launcherAppsSessionCallback_sessionOwner_canSeeSession() throws Exception {
try {
adoptShellPermissions();
final CountDownLatch countDownLatch = new CountDownLatch(1);
final int expectedSessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Context context = InstrumentationRegistry
.getInstrumentation()
.getContext();
final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
final PackageInstaller.SessionCallback
sessionCallback = new PackageInstaller.SessionCallback() {
@Override
public void onCreated(int sessionId) {
// No-op
}
@Override
public void onBadgingChanged(int sessionId) {
// No-op
}
@Override
public void onActiveChanged(int sessionId, boolean active) {
// No-op
}
@Override
public void onProgressChanged(int sessionId, float progress) {
// No-op
}
@Override
public void onFinished(int sessionId, boolean success) {
if (sessionId != expectedSessionId) {
return;
}
launcherApps.unregisterPackageInstallerSessionCallback(this);
countDownLatch.countDown();
}
};
launcherApps.registerPackageInstallerSessionCallback(context.getMainExecutor(),
sessionCallback);
commitSession(expectedSessionId);
assertTrue(countDownLatch.await(5, TimeUnit.SECONDS));
} finally {
runShellCommand("pm uninstall " + TestApp.A);
dropShellPermissions();
}
}
private Result sendCommandAndWaitForLauncherAppsSessionCallback(String sourcePackageName,
int expectedSessionId) throws Exception {
final Bundle extra = new Bundle();
extra.putInt(EXTRA_ID, expectedSessionId);
final Result result = sendCommand(sourcePackageName, /* targetPackageName */ null,
/* targetUid */ INVALID_UID, extra, ACTION_AWAIT_LAUNCHER_APPS_SESSION_CALLBACK,
/* waitForReady */ true);
return result;
}
@Test
public void launcherApps_getAllPkgInstallerSessions_queriesNothing_cannotSeeSessions()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_ALL_PACKAGE_INSTALLER_SESSIONS,
QUERIES_NOTHING, SessionInfo.INVALID_ID);
assertSessionNotVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void launcherApps_getAllPkgInstallerSessions_queriesNothingHasPermission_canSeeSessions()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_ALL_PACKAGE_INSTALLER_SESSIONS,
QUERIES_NOTHING_PERM, SessionInfo.INVALID_ID);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void launcherApps_getAllPkgInstallerSessions_queriesPackage_canSeeSessions()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_ALL_PACKAGE_INSTALLER_SESSIONS,
QUERIES_PACKAGE, SessionInfo.INVALID_ID);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void launcherApps_getAllPkgInstallerSessions_queriesNothingTargetsQ_canSeeSessions()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_ALL_PACKAGE_INSTALLER_SESSIONS,
QUERIES_NOTHING_Q, SessionInfo.INVALID_ID);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void launcherApps_getAllPkgInstallerSessions_sessionOwner_canSeeSessions()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final LauncherApps launcherApps = InstrumentationRegistry
.getInstrumentation()
.getContext()
.getSystemService(LauncherApps.class);
final Integer[] sessionIds = launcherApps.getAllPackageInstallerSessions().stream()
.map(i -> i.getSessionId())
.distinct()
.toArray(Integer[]::new);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getSessionInfo_queriesNothing_cannotSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_SESSION_INFO,
QUERIES_NOTHING, sessionId);
assertSessionNotVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getSessionInfo_queriesNothingHasPermission_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_SESSION_INFO,
QUERIES_NOTHING_PERM, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getSessionInfo_queriesPackage_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_SESSION_INFO,
QUERIES_PACKAGE, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getSessionInfo_queriesNothingTargetsQ_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_SESSION_INFO,
QUERIES_NOTHING_Q, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getSessionInfo_sessionOwner_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final PackageInstaller installer = InstrumentationRegistry
.getInstrumentation()
.getContext()
.getPackageManager()
.getPackageInstaller();
final SessionInfo info = installer.getSessionInfo(sessionId);
assertThat(info, IsNull.notNullValue());
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getStagedSessions_queriesNothing_cannotSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A).setStaged()
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_STAGED_SESSIONS,
QUERIES_NOTHING, sessionId);
assertSessionNotVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getStagedSessions_queriesNothingHasPermission_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A).setStaged()
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_STAGED_SESSIONS,
QUERIES_NOTHING_PERM, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getStagedSessions_queriesPackage_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A).setStaged()
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_STAGED_SESSIONS,
QUERIES_PACKAGE, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getStagedSessions_queriesNothingTargetsQ_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A).setStaged()
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_STAGED_SESSIONS,
QUERIES_NOTHING_Q, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getStagedSessions_sessionOwner_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A).setStaged()
.createSession();
final PackageInstaller installer = InstrumentationRegistry
.getInstrumentation()
.getContext()
.getPackageManager()
.getPackageInstaller();
final Integer[] sessionIds = installer.getStagedSessions().stream()
.map(i -> i.getSessionId())
.distinct()
.toArray(Integer[]::new);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getAllSessions_queriesNothing_cannotSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_ALL_SESSIONS,
QUERIES_NOTHING, sessionId);
assertSessionNotVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getAllSessions_queriesNothingHasPermission_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_ALL_SESSIONS,
QUERIES_NOTHING_PERM, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getAllSessions_queriesPackage_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_ALL_SESSIONS,
QUERIES_PACKAGE, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getAllSessions_queriesNothingTargetsQ_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final Integer[] sessionIds = getSessionInfos(ACTION_GET_ALL_SESSIONS,
QUERIES_NOTHING_Q, sessionId);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
@Test
public void packageInstaller_getAllSessions_sessionOwner_canSeeSession()
throws Exception {
try {
adoptShellPermissions();
final int sessionId = Install.single(TestApp.A1).setPackageName(TestApp.A)
.createSession();
final PackageInstaller installer = InstrumentationRegistry
.getInstrumentation()
.getContext()
.getPackageManager()
.getPackageInstaller();
final Integer[] sessionIds = installer.getAllSessions().stream()
.map(i -> i.getSessionId())
.distinct()
.toArray(Integer[]::new);
assertSessionVisible(sessionIds, sessionId);
} finally {
cleanUpSessions();
dropShellPermissions();
}
}
private Integer[] getSessionInfos(String action, String sourcePackageName, int sessionId)
throws Exception {
final Bundle extraData = new Bundle();
extraData.putInt(EXTRA_ID, sessionId);
final Bundle response = sendCommandBlocking(sourcePackageName, /* targetPackageName */ null,
extraData, action);
final List<Parcelable> parcelables = response.getParcelableArrayList(
Intent.EXTRA_RETURN_RESULT);
return parcelables.stream()
.map(i -> (i == null ? SessionInfo.INVALID_ID : ((SessionInfo) i).getSessionId()))
.distinct()
.toArray(Integer[]::new);
}
private void assertSessionVisible(Integer[] sessionIds, int sessionId) {
if (!sGlobalFeatureEnabled) {
return;
}
assertThat(sessionIds, hasItemInArray(sessionId));
}
private void assertSessionNotVisible(Integer[] sessionIds, int sessionId) {
if (!sGlobalFeatureEnabled) {
return;
}
assertThat(sessionIds, not(hasItemInArray(sessionId)));
}
private static void commitSession(int sessionId) throws Exception {
final PackageInstaller.Session session =
InstallUtils.openPackageInstallerSession(sessionId);
final LocalIntentSender sender = new LocalIntentSender();
session.commit(sender.getIntentSender());
InstallUtils.assertStatusSuccess(sender.getResult());
}
private void adoptShellPermissions() {
InstrumentationRegistry
.getInstrumentation()
.getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.INSTALL_PACKAGES);
}
private void dropShellPermissions() {
InstrumentationRegistry
.getInstrumentation()
.getUiAutomation()
.dropShellPermissionIdentity();
}
private void cleanUpSessions() {
InstallUtils.getPackageInstaller().getMySessions().forEach(info -> {
try {
InstallUtils.getPackageInstaller().abandonSession(info.getSessionId());
} catch (Exception ignore) {
}
});
}
@Test
public void queriesResolver_grantsVisibilityToProvider() throws Exception {
assertNotVisible(QUERIES_NOTHING_PROVIDER, QUERIES_NOTHING_PERM);
String[] result = sendCommandBlocking(
QUERIES_NOTHING_PERM, QUERIES_NOTHING_PROVIDER, null, ACTION_QUERY_RESOLVER)
.getStringArray(Intent.EXTRA_RETURN_RESULT);
Arrays.sort(result);
assertThat(QUERIES_NOTHING_PERM + " not visible to " + QUERIES_NOTHING_PROVIDER
+ " during resolver interaction",
Arrays.binarySearch(result, QUERIES_NOTHING_PERM),
greaterThanOrEqualTo(0));
assertVisible(QUERIES_NOTHING_PROVIDER, QUERIES_NOTHING_PERM);
}
@Test
public void bindService_consistentVisibility() throws Exception {
// Ensure package visibility isn't impacted by optimization or cached result.
// Target service shouldn't be visible to app without query permission even if
// another app with query permission is binding it.
assertServiceVisible(QUERIES_NOTHING_PERM, TARGET_FILTERS);
assertServiceNotVisible(QUERIES_NOTHING, TARGET_FILTERS);
}
@Test
public void queriesPackage_getSyncAdapterTypes_canSeeSyncadapterTarget() throws Exception {
assertVisible(QUERIES_PACKAGE, TARGET_SYNCADAPTER, this::getSyncAdapterTypes);
}
@Test
public void queriesNothing_getSyncAdapterTypes_cannotSeeSyncadapterTarget() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_SYNCADAPTER, this::getSyncAdapterTypes);
assertNotVisible(QUERIES_NOTHING, TARGET_SYNCADAPTER_SHARED_USER,
this::getSyncAdapterTypes);
}
@Test
public void queriesNothingSharedUser_getSyncAdapterTypes_canSeeSyncadapterSharedUserTarget()
throws Exception {
assertVisible(QUERIES_NOTHING_SHARED_USER, TARGET_SYNCADAPTER_SHARED_USER,
this::getSyncAdapterTypes);
}
@Test
public void queriesPackage_getSyncAdapterPackages_canSeeSyncadapterTarget()
throws Exception {
assertVisible(QUERIES_PACKAGE, TARGET_SYNCADAPTER,
this::getSyncAdapterPackagesForAuthorityAsUser);
}
@Test
public void queriesNothing_getSyncAdapterPackages_cannotSeeSyncadapterTarget()
throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_SYNCADAPTER,
this::getSyncAdapterPackagesForAuthorityAsUser);
assertNotVisible(QUERIES_NOTHING, TARGET_SYNCADAPTER_SHARED_USER,
this::getSyncAdapterPackagesForAuthorityAsUser);
}
@Test
public void queriesPackage_requestSync_canSeeSyncadapterTarget()
throws Exception {
assertThat(requestSyncAndAwaitStatus(QUERIES_PACKAGE,
ACCOUNT_SYNCADAPTER, TARGET_SYNCADAPTER),
is(true));
}
@Test
public void queriesNothingSharedUser_requestSync_canSeeSyncadapterSharedUserTarget()
throws Exception {
assertThat(requestSyncAndAwaitStatus(QUERIES_NOTHING_SHARED_USER,
ACCOUNT_SYNCADAPTER_SHARED_USER, TARGET_SYNCADAPTER_SHARED_USER),
is(true));
}
@Test
public void queriesNothing_requestSync_cannotSeeSyncadapterTarget() {
assertThrows(MissingCallbackException.class,
() -> requestSyncAndAwaitStatus(QUERIES_NOTHING,
ACCOUNT_SYNCADAPTER, TARGET_SYNCADAPTER));
assertThrows(MissingCallbackException.class,
() -> requestSyncAndAwaitStatus(QUERIES_NOTHING,
ACCOUNT_SYNCADAPTER_SHARED_USER, TARGET_SYNCADAPTER_SHARED_USER));
}
@Test
public void queriesNothingSharedUser_getSyncAdapterPackages_canSeeSyncadapterSharedUserTarget()
throws Exception {
assertVisible(QUERIES_NOTHING_SHARED_USER, TARGET_SYNCADAPTER_SHARED_USER,
this::getSyncAdapterPackagesForAuthorityAsUser);
}
@Test
public void launcherAppsIsActivityEnabled_queriesActivityAction_canSeeActivity()
throws Exception {
final ComponentName targetFilters = ComponentName.createRelative(TARGET_FILTERS,
ACTIVITY_CLASS_DUMMY_ACTIVITY);
assertThat(QUERIES_ACTIVITY_ACTION + " should be able to see " + targetFilters,
launcherAppsIsActivityEnabled(QUERIES_ACTIVITY_ACTION, targetFilters),
is(true));
}
@Test
public void launcherAppsIsActivityEnabled_queriesNothing_cannotSeeActivity()
throws Exception {
final ComponentName targetFilters = ComponentName.createRelative(TARGET_FILTERS,
ACTIVITY_CLASS_DUMMY_ACTIVITY);
assertThat(QUERIES_ACTIVITY_ACTION + " should not be able to see " + targetFilters,
launcherAppsIsActivityEnabled(QUERIES_NOTHING, targetFilters),
is(false));
}
@Test
public void launcherAppsGetSuspendedPackageLauncherExtras_queriesNothingHasPerm_canGetExtras()
throws Exception {
try {
setPackagesSuspendedWithLauncherExtras(/* suspend */ true,
Arrays.asList(TARGET_NO_API), /* extras */ true);
Assert.assertNotNull(launcherAppsGetSuspendedPackageLauncherExtras(QUERIES_NOTHING_PERM,
TARGET_NO_API));
} finally {
setPackagesSuspended(/* suspend */ false, Arrays.asList(TARGET_NO_API));
}
}
@Test
public void launcherAppsGetSuspendedPackageLauncherExtras_queriesNothing_cannotGetExtras()
throws Exception {
try {
setPackagesSuspendedWithLauncherExtras(/* suspend */ true,
Arrays.asList(TARGET_NO_API), /* extras */ true);
Assert.assertNull(launcherAppsGetSuspendedPackageLauncherExtras(QUERIES_NOTHING,
TARGET_NO_API));
} finally {
setPackagesSuspended(/* suspend */ false, Arrays.asList(TARGET_NO_API));
}
}
@Test
public void launcherAppsShouldHideFromSuggestions_queriesPackage_canSeeNoApi()
throws Exception {
setDistractingPackageRestrictions(new String[]{TARGET_NO_API},
PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS);
try {
final boolean hideFromSuggestions = shouldHideFromSuggestions(
QUERIES_PACKAGE, TARGET_NO_API);
assertThat(hideFromSuggestions, is(true));
} finally {
setDistractingPackageRestrictions(new String[]{TARGET_NO_API},
PackageManager.RESTRICTION_NONE);
}
}
@Test
public void launcherAppsShouldHideFromSuggestions_queriesNothing_cannotSeeNoApi()
throws Exception {
setDistractingPackageRestrictions(new String[]{TARGET_NO_API},
PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS);
try {
final boolean hideFromSuggestions = shouldHideFromSuggestions(
QUERIES_NOTHING, TARGET_NO_API);
assertThat(hideFromSuggestions, is(false));
} finally {
setDistractingPackageRestrictions(new String[]{TARGET_NO_API},
PackageManager.RESTRICTION_NONE);
}
}
@Test
public void queriesPackage_canSeeAppWidgetProviderTarget() throws Exception {
assumeTrue(InstrumentationRegistry.getInstrumentation().getContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS));
assertVisible(QUERIES_PACKAGE, TARGET_APPWIDGETPROVIDER,
this::getInstalledAppWidgetProviders);
}
@Test
public void queriesNothing_cannotSeeAppWidgetProviderTarget() throws Exception {
assumeTrue(InstrumentationRegistry.getInstrumentation().getContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS));
assertNotVisible(QUERIES_NOTHING, TARGET_APPWIDGETPROVIDER,
this::getInstalledAppWidgetProviders);
assertNotVisible(QUERIES_NOTHING, TARGET_APPWIDGETPROVIDER_SHARED_USER,
this::getInstalledAppWidgetProviders);
}
@Test
public void queriesNothingSharedUser_canSeeAppWidgetProviderSharedUserTarget()
throws Exception {
assumeTrue(InstrumentationRegistry.getInstrumentation().getContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS));
assertVisible(QUERIES_NOTHING_SHARED_USER, TARGET_APPWIDGETPROVIDER_SHARED_USER,
this::getInstalledAppWidgetProviders);
}
@Test
public void queriesNothing_cannotSeeSharedLibraryDependentPackages() throws Exception {
assertNotVisible(QUERIES_NOTHING, TARGET_NO_API, this::getSharedLibraryDependentPackages);
assertNotVisible(QUERIES_NOTHING, TARGET_FILTERS, this::getSharedLibraryDependentPackages);
assertNotVisible(QUERIES_NOTHING, TARGET_SHARED_USER,
this::getSharedLibraryDependentPackages);
}
@Test
public void queriesPackage_canSeeSharedLibraryDependentPackages() throws Exception {
assertVisible(QUERIES_PACKAGE, TARGET_NO_API, this::getSharedLibraryDependentPackages);
assertVisible(QUERIES_PACKAGE, TARGET_SHARED_USER, this::getSharedLibraryDependentPackages);
}
@Test
public void queriesNothingSharedUser_canSeeSharedUserInSharedLibraryDependentPackages()
throws Exception {
assertVisible(QUERIES_NOTHING_SHARED_USER, TARGET_SHARED_USER,
this::getSharedLibraryDependentPackages);
}
@Test
public void queriesNothing_cannotSeePreferredActivityTarget() throws Exception {
addPreferredActivity();
try {
assertNotVisible(QUERIES_NOTHING, TARGET_PREFERRED_ACTIVITY,
this::getPreferredActivities);
} finally {
clearPreferredActivity();
}
}
@Test
public void queriesPackage_canSeePreferredActivityTarget() throws Exception {
addPreferredActivity();
try {
assertVisible(QUERIES_PACKAGE, TARGET_PREFERRED_ACTIVITY,
this::getPreferredActivities);
} finally {
clearPreferredActivity();
}
}
@Test
public void queriesNothing_setInstallerPackageName_targetIsNoApi_throwsException() {
final Exception ex = assertThrows(IllegalArgumentException.class,
() -> setInstallerPackageName(QUERIES_NOTHING, TARGET_NO_API, QUERIES_NOTHING));
assertThat(ex.getMessage(), containsString(TARGET_NO_API));
}
@Test
public void queriesNothing_setInstallerPackageName_installerIsNoApi_throwsException() {
final Exception ex = assertThrows(IllegalArgumentException.class,
() -> setInstallerPackageName(QUERIES_NOTHING, QUERIES_NOTHING, TARGET_NO_API));
assertThat(ex.getMessage(), containsString(TARGET_NO_API));
}
@Test
public void queriesPackageHasProvider_checkUriPermission_canSeeNoApi() throws Exception {
final int permissionResult = checkUriPermission(QUERIES_PACKAGE_PROVIDER, TARGET_NO_API);
assertThat(permissionResult, is(PackageManager.PERMISSION_GRANTED));
}
@Test
public void queriesPackageHasProvider_checkUriPermission_cannotSeeFilters() throws Exception {
final int permissionResult = checkUriPermission(QUERIES_PACKAGE_PROVIDER, TARGET_FILTERS);
assertThat(permissionResult, is(PackageManager.PERMISSION_DENIED));
}
@Test
public void queriesPackageHasProvider_grantUriPermission_canSeeNoApi() throws Exception {
try {
grantUriPermission(QUERIES_PACKAGE_PROVIDER, TARGET_NO_API);
assertThat(InstrumentationRegistry.getInstrumentation().getContext()
.checkUriPermission(
Uri.parse("content://" + QUERIES_PACKAGE_PROVIDER),
0 /* pid */,
sPm.getPackageUid(TARGET_NO_API, 0 /* flags */),
Intent.FLAG_GRANT_READ_URI_PERMISSION),
is(PackageManager.PERMISSION_GRANTED));
} finally {
revokeUriPermission(QUERIES_PACKAGE_PROVIDER);
}
}
@Test
public void queriesPackageHasProvider_grantUriPermission_cannotSeeFilters() throws Exception {
try {
grantUriPermission(QUERIES_PACKAGE_PROVIDER, TARGET_FILTERS);
assertThat(InstrumentationRegistry.getInstrumentation().getContext()
.checkUriPermission(
Uri.parse("content://" + QUERIES_PACKAGE_PROVIDER),
0 /* pid */,
sPm.getPackageUid(TARGET_FILTERS, 0 /* flags */),
Intent.FLAG_GRANT_READ_URI_PERMISSION),
is(PackageManager.PERMISSION_DENIED));
} finally {
revokeUriPermission(QUERIES_PACKAGE_PROVIDER);
}
}
@Test
public void canPackageQuery_queriesActivityAction_canSeeFilters() throws Exception {
assertThat(sPm.canPackageQuery(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS),
is(true));
}
@Test
public void canPackageQuery_queriesNothing_cannotSeeFilters() throws Exception {
assertThat(sPm.canPackageQuery(QUERIES_NOTHING, TARGET_FILTERS),
is(false));
}
@Test
public void canPackageQuery_withNonexistentPackages() {
assertThrows(PackageManager.NameNotFoundException.class,
() -> sPm.canPackageQuery(
TEST_NONEXISTENT_PACKAGE_NAME_1, TEST_NONEXISTENT_PACKAGE_NAME_2));
assertThrows(PackageManager.NameNotFoundException.class,
() -> sPm.canPackageQuery(
QUERIES_NOTHING_PERM, TEST_NONEXISTENT_PACKAGE_NAME_2));
assertThrows(PackageManager.NameNotFoundException.class,
() -> sPm.canPackageQuery(
TEST_NONEXISTENT_PACKAGE_NAME_1, TARGET_FILTERS));
}
@Test
public void canPackageQuery_callerHasNoPackageVisibility() {
assertThrows(PackageManager.NameNotFoundException.class,
() -> canPackageQuery(
QUERIES_NOTHING, QUERIES_ACTIVITY_ACTION, TARGET_FILTERS));
assertThrows(PackageManager.NameNotFoundException.class,
() -> canPackageQuery(
QUERIES_NOTHING_SHARED_USER, QUERIES_PACKAGE, TARGET_SHARED_USER));
}
@Test
public void checkPackage_queriesNothing_validateFailed() {
// Using ROOT_UID here to pass the check in #verifyAndGetBypass, this is intended by design.
assertThrows(SecurityException.class,
() -> checkPackage(QUERIES_NOTHING, TARGET_FILTERS, ROOT_UID));
}
@Test
public void checkPackage_queriesNothing_targetIsNotExisting_validateFailed() {
// Using ROOT_UID here to pass the check in #verifyAndGetBypass, this is intended by design.
assertThrows(SecurityException.class,
() -> checkPackage(QUERIES_NOTHING, TEST_NONEXISTENT_PACKAGE_NAME_1, ROOT_UID));
}
@Test
public void checkPackage_queriesNothingHasPerm_validateSuccessful() throws Exception {
// Using ROOT_UID here to pass the check in #verifyAndGetBypass, this is intended by design.
assertThat(checkPackage(QUERIES_NOTHING_PERM, TARGET_FILTERS, ROOT_UID), is(true));
}
@Test
public void checkPackage_queriesNothingHasPerm_targetIsNotExisting_validateFailed()
throws Exception {
// Using ROOT_UID here to pass the check in #verifyAndGetBypass, this is intended by design.
assertThrows(SecurityException.class,
() -> checkPackage(QUERIES_NOTHING_PERM, TEST_NONEXISTENT_PACKAGE_NAME_1,
ROOT_UID));
}
@Test
public void pendingIntent_getCreatorPackage_queriesPackage_canSeeNoApi()
throws Exception {
final PendingIntent pendingIntent = getPendingIntentActivity(TARGET_NO_API);
assertThat(getPendingIntentCreatorPackage(QUERIES_PACKAGE, pendingIntent),
is(TARGET_NO_API));
}
@Test
public void pendingIntent_getCreatorPackage_queriesNothing_cannotSeeNoApi()
throws Exception {
final PendingIntent pendingIntent = getPendingIntentActivity(TARGET_NO_API);
assertThat(getPendingIntentCreatorPackage(QUERIES_NOTHING, pendingIntent),
is(emptyOrNullString()));
}
@Test
public void makeUidVisible_throwsException() throws Exception {
final int recipientUid = sPm.getPackageUid(
QUERIES_NOTHING, PackageManager.PackageInfoFlags.of(0));
final int visibleUid = sPm.getPackageUid(
TARGET_NO_API, PackageManager.PackageInfoFlags.of(0));
assertThrows(SecurityException.class,
() -> sPm.makeUidVisible(recipientUid, visibleUid));
}
@Test
public void makeUidVisible_queriesNothing_canSeeStub() throws Exception {
ensurePackageIsInstalled(TARGET_STUB, TARGET_STUB_APK);
try {
assertNotVisible(QUERIES_NOTHING, TARGET_STUB);
final int recipientUid = sPm.getPackageUid(
QUERIES_NOTHING, PackageManager.PackageInfoFlags.of(0));
final int visibleUid = sPm.getPackageUid(
TARGET_STUB, PackageManager.PackageInfoFlags.of(0));
SystemUtil.runWithShellPermissionIdentity(
() -> sPm.makeUidVisible(recipientUid, visibleUid),
Manifest.permission.MAKE_UID_VISIBLE);
assertVisible(QUERIES_NOTHING, TARGET_STUB);
} finally {
ensurePackageIsNotInstalled(TARGET_STUB);
}
}
private void assertNotVisible(String sourcePackageName, String targetPackageName)
throws Exception {
if (!sGlobalFeatureEnabled) return;
try {
getPackageInfo(sourcePackageName, targetPackageName);
fail(sourcePackageName + " should not be able to see " + targetPackageName);
} catch (PackageManager.NameNotFoundException ignored) {
}
}
private void assertServiceVisible(String sourcePackageName, String targetPackageName)
throws Exception {
if (!sGlobalFeatureEnabled) return;
assertTrue(bindService(sourcePackageName, targetPackageName));
}
private void assertServiceNotVisible(String sourcePackageName, String targetPackageName)
throws Exception {
if (!sGlobalFeatureEnabled) return;
assertFalse(bindService(sourcePackageName, targetPackageName));
}
interface ThrowingBiFunction<T, U, R> {
R apply(T arg1, U arg2) throws Exception;
}
interface ThrowingFunction<T, R> {
R apply(T arg1) throws Exception;
}
private void assertNotQueryable(String sourcePackageName, String targetPackageName,
String intentAction, ThrowingBiFunction<String, Intent, String[]> commandMethod)
throws Exception {
if (!sGlobalFeatureEnabled) return;
Intent intent = new Intent(intentAction);
String[] queryablePackageNames = commandMethod.apply(sourcePackageName, intent);
for (String packageName : queryablePackageNames) {
if (packageName.contentEquals(targetPackageName)) {
fail(sourcePackageName + " should not be able to query " + targetPackageName +
" via " + intentAction);
}
}
}
private void assertQueryable(String sourcePackageName, String targetPackageName,
String intentAction, ThrowingBiFunction<String, Intent, String[]> commandMethod)
throws Exception {
if (!sGlobalFeatureEnabled) return;
Intent intent = new Intent(intentAction);
String[] queryablePackageNames = commandMethod.apply(sourcePackageName, intent);
for (String packageName : queryablePackageNames) {
if (packageName.contentEquals(targetPackageName)) {
return;
}
}
fail(sourcePackageName + " should be able to query " + targetPackageName + " via "
+ intentAction);
}
private void assertVisible(String sourcePackageName, String targetPackageName,
ThrowingFunction<String, String[]> commandMethod) throws Exception {
if (!sGlobalFeatureEnabled) return;
final String[] packageNames = commandMethod.apply(sourcePackageName);
assertThat("The list of package names should not be null",
packageNames, notNullValue());
assertThat(sourcePackageName + " should be able to see " + targetPackageName,
packageNames, hasItemInArray(targetPackageName));
}
private void assertNotVisible(String sourcePackageName, String targetPackageName,
ThrowingFunction<String, String[]> commandMethod) throws Exception {
if (!sGlobalFeatureEnabled) return;
final String[] packageNames = commandMethod.apply(sourcePackageName);
assertThat("The list of package names should not be null",
packageNames, notNullValue());
assertThat(sourcePackageName + " should not be able to see " + targetPackageName,
packageNames, not(hasItemInArray(targetPackageName)));
}
private void assertVisible(String sourcePackageName, String targetPackageName,
ThrowingBiFunction<String, String, String[]> commandMethod) throws Exception {
if (!sGlobalFeatureEnabled) return;
final String[] packageNames = commandMethod.apply(sourcePackageName, targetPackageName);
assertThat(sourcePackageName + " should be able to see " + targetPackageName,
packageNames, hasItemInArray(targetPackageName));
}
private void assertNotVisible(String sourcePackageName, String targetPackageName,
ThrowingBiFunction<String, String, String[]> commandMethod) throws Exception {
if (!sGlobalFeatureEnabled) return;
final String[] packageNames = commandMethod.apply(sourcePackageName, targetPackageName);
assertThat(sourcePackageName + " should not be able to see " + targetPackageName,
packageNames, not(hasItemInArray(targetPackageName)));
}
private void assertBroadcastSuspendedVisible(String sourcePackageName,
List<String> expectedVisiblePackages, List<String> packagesToSuspend)
throws Exception {
final Bundle extras = new Bundle();
extras.putStringArray(EXTRA_PACKAGES, packagesToSuspend.toArray(new String[] {}));
final Result result = sendCommand(sourcePackageName, /* targetPackageName */ null,
/* targetUid */ INVALID_UID, extras, Constants.ACTION_AWAIT_PACKAGES_SUSPENDED,
/* waitForReady */ true);
try {
setPackagesSuspended(true, packagesToSuspend);
final String[] suspendedPackages = result.await().getStringArray(EXTRA_PACKAGES);
assertThat(suspendedPackages, arrayContainingInAnyOrder(
expectedVisiblePackages.toArray()));
} finally {
setPackagesSuspended(false, packagesToSuspend);
}
}
private String[] getInstalledAccessibilityServices (String sourcePackageName)
throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, null /*targetPackageName*/,
null /*queryIntent*/, ACTION_GET_INSTALLED_ACCESSIBILITYSERVICES_PACKAGES);
return response.getStringArray(Intent.EXTRA_RETURN_RESULT);
}
private PackageInfo getPackageInfo(String sourcePackageName, String targetPackageName)
throws Exception {
Bundle response = sendCommandBlocking(sourcePackageName, targetPackageName,
null /*queryIntent*/, ACTION_GET_PACKAGE_INFO);
return response.getParcelable(Intent.EXTRA_RETURN_RESULT);
}
private String[] getPackagesForUid(String sourcePackageName, int targetUid)
throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, targetUid,
/* intentExtra */ null, ACTION_GET_PACKAGES_FOR_UID);
return response.getStringArray(Intent.EXTRA_RETURN_RESULT);
}
private String getNameForUid(String sourcePackageName, int targetUid) throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, targetUid,
/* intentExtra */ null, ACTION_GET_NAME_FOR_UID);
return response.getString(Intent.EXTRA_RETURN_RESULT);
}
private String[] getNamesForUids(String sourcePackageName, int targetUid) throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, targetUid,
/* intentExtra */ null, ACTION_GET_NAMES_FOR_UIDS);
return response.getStringArray(Intent.EXTRA_RETURN_RESULT);
}
private int checkSignatures(String sourcePackageName, int targetUid) throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, targetUid,
/* intentExtra */ null, ACTION_CHECK_SIGNATURES);
return response.getInt(Intent.EXTRA_RETURN_RESULT);
}
private boolean hasSigningCertificate(String sourcePackageName, int targetUid, byte[] cert)
throws Exception {
final Bundle extra = new Bundle();
extra.putByteArray(EXTRA_CERT, cert);
final Bundle response = sendCommandBlocking(sourcePackageName, targetUid, extra,
ACTION_HAS_SIGNING_CERTIFICATE);
return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
}
private List<Certificate> convertSignaturesToCertificates(Signature[] signatures)
throws Exception {
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
ArrayList<Certificate> certs = new ArrayList<>(signatures.length);
for (Signature signature : signatures) {
final InputStream is = new ByteArrayInputStream(signature.toByteArray());
final X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
certs.add(cert);
}
return certs;
}
private boolean checkPackage(String sourcePackageName, String targetPackageName, int targetUid)
throws Exception {
final Bundle extra = new Bundle();
extra.putInt(EXTRA_UID, targetUid);
final Bundle response = sendCommandBlocking(sourcePackageName, targetPackageName, extra,
ACTION_CHECK_PACKAGE);
return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
}
private PackageInfo startForResult(String sourcePackageName, String targetPackageName)
throws Exception {
Bundle response = sendCommandBlocking(sourcePackageName, targetPackageName,
null /*queryIntent*/, ACTION_START_FOR_RESULT);
return response.getParcelable(Intent.EXTRA_RETURN_RESULT);
}
private PackageInfo startSenderForResult(String sourcePackageName, String targetPackageName)
throws Exception {
PendingIntent pendingIntent = PendingIntent.getActivity(
InstrumentationRegistry.getInstrumentation().getContext(), 100,
new Intent("android.appenumeration.cts.action.SEND_RESULT").setComponent(
new ComponentName(targetPackageName,
"android.appenumeration.cts.TestActivity")),
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
Bundle response = sendCommandBlocking(sourcePackageName, targetPackageName,
pendingIntent /*queryIntent*/, Constants.ACTION_START_SENDER_FOR_RESULT);
return response.getParcelable(Intent.EXTRA_RETURN_RESULT);
}
private String[] queryIntentActivities(String sourcePackageName, Intent queryIntent)
throws Exception {
Bundle response =
sendCommandBlocking(sourcePackageName, null, queryIntent, ACTION_QUERY_ACTIVITIES);
return response.getStringArray(Intent.EXTRA_RETURN_RESULT);
}
private String[] queryIntentServices(String sourcePackageName, Intent queryIntent)
throws Exception {
Bundle response = sendCommandBlocking(sourcePackageName, null, queryIntent,
ACTION_QUERY_SERVICES);
return response.getStringArray(Intent.EXTRA_RETURN_RESULT);
}
private String[] queryIntentProviders(String sourcePackageName, Intent queryIntent)
throws Exception {
Bundle response = sendCommandBlocking(sourcePackageName, null, queryIntent,
ACTION_QUERY_PROVIDERS);
return response.getStringArray(Intent.EXTRA_RETURN_RESULT);
}
private String[] getInstalledPackages(String sourcePackageNames, int flags) throws Exception {
Bundle response = sendCommandBlocking(sourcePackageNames, null,
new Intent().putExtra(EXTRA_FLAGS, flags), ACTION_GET_INSTALLED_PACKAGES);
return response.getStringArray(Intent.EXTRA_RETURN_RESULT);
}
private void startExplicitIntentViaComponent(String sourcePackage, String targetPackage)
throws Exception {
sendCommandBlocking(sourcePackage, targetPackage,
new Intent().setComponent(new ComponentName(targetPackage,
ACTIVITY_CLASS_DUMMY_ACTIVITY)),
ACTION_START_DIRECTLY);
}
private void startExplicitIntentViaPackageName(String sourcePackage, String targetPackage)
throws Exception {
sendCommandBlocking(sourcePackage, targetPackage,
new Intent().setPackage(targetPackage),
ACTION_START_DIRECTLY);
}
private void startImplicitIntent(String sourcePackage) throws Exception {
sendCommandBlocking(sourcePackage, TARGET_FILTERS, new Intent(ACTION_MANIFEST_ACTIVITY),
ACTION_START_DIRECTLY);
}
private boolean bindService(String sourcePackageName, String targetPackageName)
throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, targetPackageName,
/* intentExtra */ null, ACTION_BIND_SERVICE);
return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
}
private String[] getSyncAdapterTypes(String sourcePackageName) throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, /* targetPackageName */ null,
/* intentExtra */ null, ACTION_GET_SYNCADAPTER_TYPES);
final List<Parcelable> parcelables = response.getParcelableArrayList(
Intent.EXTRA_RETURN_RESULT);
return parcelables.stream()
.map(parcelable -> ((SyncAdapterType) parcelable).getPackageName())
.distinct()
.toArray(String[]::new);
}
private String[] getInstalledAppWidgetProviders(String sourcePackageName) throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, /* targetPackageName */ null,
/* intentExtra */ null, ACTION_GET_INSTALLED_APPWIDGET_PROVIDERS);
final List<Parcelable> parcelables = response.getParcelableArrayList(
Intent.EXTRA_RETURN_RESULT);
return parcelables.stream()
.map(parcelable -> ((AppWidgetProviderInfo) parcelable).provider.getPackageName())
.distinct()
.toArray(String[]::new);
}
private String[] getSyncAdapterPackagesForAuthorityAsUser(String sourcePackageName,
String targetPackageName) throws Exception {
final Bundle extraData = new Bundle();
extraData.putString(EXTRA_AUTHORITY, targetPackageName + ".authority");
extraData.putInt(Intent.EXTRA_USER, Process.myUserHandle().getIdentifier());
final Bundle response = sendCommandBlocking(sourcePackageName, /* targetPackageName */ null,
extraData, ACTION_GET_SYNCADAPTER_PACKAGES_FOR_AUTHORITY);
return response.getStringArray(Intent.EXTRA_PACKAGES);
}
private boolean requestSyncAndAwaitStatus(String sourcePackageName, Account account,
String targetPackageName) throws Exception {
final Bundle extraData = new Bundle();
extraData.putParcelable(EXTRA_ACCOUNT, account);
extraData.putString(EXTRA_AUTHORITY, targetPackageName + ".authority");
final Bundle response = sendCommandBlocking(sourcePackageName, /* targetPackageName */ null,
extraData, ACTION_REQUEST_SYNC_AND_AWAIT_STATUS);
return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
}
private void setPackagesSuspended(boolean suspend, List<String> packages) {
setPackagesSuspendedWithLauncherExtras(suspend, packages, /* persistableBundle */ false);
}
private void setPackagesSuspendedWithLauncherExtras(boolean suspend, List<String> packages,
boolean extras) {
final StringBuilder cmd = new StringBuilder("pm ");
if (suspend) {
cmd.append("suspend");
} else {
cmd.append("unsuspend");
}
cmd.append(" --user cur");
if (extras) {
cmd.append(" --les foo bar");
}
packages.stream().forEach(p -> cmd.append(" ").append(p));
runShellCommand(cmd.toString());
}
private boolean launcherAppsIsActivityEnabled(String sourcePackageName,
ComponentName componentName) throws Exception {
final Bundle extraData = new Bundle();
extraData.putString(Intent.EXTRA_COMPONENT_NAME, componentName.flattenToString());
final Bundle response = sendCommandBlocking(sourcePackageName, /* targetPackageName */ null,
extraData, ACTION_LAUNCHER_APPS_IS_ACTIVITY_ENABLED);
return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
}
private Bundle launcherAppsGetSuspendedPackageLauncherExtras(String sourcePackageName,
String targetPackageName) throws Exception {
final Bundle response = sendCommandBlocking(sourcePackageName, targetPackageName,
/* extraData */ null, ACTION_LAUNCHER_APPS_GET_SUSPENDED_PACKAGE_LAUNCHER_EXTRAS);
return response.getBundle(Intent.EXTRA_RETURN_RESULT);
}
private String[] getSharedLibraryDependentPackages(String sourcePackageName) throws Exception {
final Bundle extraData = new Bundle();
final Bundle response = sendCommandBlocking(sourcePackageName, TEST_SHARED_LIB_NAME,
extraData, ACTION_GET_SHAREDLIBRARY_DEPENDENT_PACKAGES);
return response.getStringArray(Intent.EXTRA_PACKAGES);
}
private String[] getPreferredActivities(String sourcePackageName) throws Exception {
final Bundle extraData = new Bundle();
final Bundle response = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
extraData, ACTION_GET_PREFERRED_ACTIVITIES);
return response.getStringArray(Intent.EXTRA_PACKAGES);
}
private void setInstallerPackageName(String sourcePackageName, String targetPackageName,
String installerPackageName) throws Exception {
final Bundle extraData = new Bundle();
extraData.putString(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName);
sendCommandBlocking(sourcePackageName, targetPackageName,
extraData, ACTION_SET_INSTALLER_PACKAGE_NAME);
}
private void setDistractingPackageRestrictions(String[] packagesToRestrict,
int distractionFlags) throws Exception {
final String[] failed = SystemUtil.callWithShellPermissionIdentity(
() -> sPm.setDistractingPackageRestrictions(packagesToRestrict, distractionFlags));
assertThat(failed, emptyArray());
}
private boolean shouldHideFromSuggestions(String sourcePackageName, String targetPackageName)
throws Exception {
final Bundle extraData = new Bundle();
extraData.putInt(Intent.EXTRA_USER, Process.myUserHandle().getIdentifier());
final Bundle response = sendCommandBlocking(sourcePackageName, targetPackageName, extraData,
ACTION_LAUNCHER_APPS_SHOULD_HIDE_FROM_SUGGESTIONS);
return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
}
private int checkUriPermission(String sourcePackageName, String targetPackageName)
throws Exception {
final int targetUid = sPm.getPackageUid(targetPackageName, /* flags */ 0);
final Bundle extraData = new Bundle();
extraData.putString(EXTRA_AUTHORITY, sourcePackageName);
final Result result = sendCommand(sourcePackageName, targetPackageName, targetUid,
extraData, ACTION_CHECK_URI_PERMISSION, /* waitForReady */ false);
final Bundle response = result.await();
return response.getInt(Intent.EXTRA_RETURN_RESULT);
}
private void grantUriPermission(String providerPackageName, String targetPackageName)
throws Exception {
final Bundle extraData = new Bundle();
extraData.putString(EXTRA_AUTHORITY, providerPackageName);
sendCommandBlocking(providerPackageName, targetPackageName, extraData,
ACTION_GRANT_URI_PERMISSION);
}
private void revokeUriPermission(String providerPackageName) throws Exception {
final Bundle extraData = new Bundle();
extraData.putString(EXTRA_AUTHORITY, providerPackageName);
sendCommandBlocking(providerPackageName, null /* targetPackageName */, extraData,
ACTION_REVOKE_URI_PERMISSION);
}
private boolean canPackageQuery(String callerPackageName, String sourcePackageName,
String targetPackageName) throws Exception {
final Bundle extraData = new Bundle();
extraData.putString(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
final Bundle response = sendCommandBlocking(callerPackageName, sourcePackageName,
extraData, ACTION_CAN_PACKAGE_QUERY);
return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
}
private PendingIntent getPendingIntentActivity(String sourcePackageName) throws Exception {
final Bundle bundle = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
null /* intentExtra */, ACTION_PENDING_INTENT_GET_ACTIVITY);
return bundle.getParcelable(EXTRA_PENDING_INTENT);
}
private String getPendingIntentCreatorPackage(String sourcePackageName,
PendingIntent pendingIntent) throws Exception {
final Bundle bundle = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
pendingIntent, ACTION_PENDING_INTENT_GET_CREATOR_PACKAGE);
return bundle.getString(Intent.EXTRA_PACKAGE_NAME);
}
interface Result {
Bundle await() throws Exception;
}
private Result sendCommand(String sourcePackageName, @Nullable String targetPackageName,
int targetUid, @Nullable Parcelable intentExtra, String action, boolean waitForReady)
throws Exception {
final Intent intent = new Intent(action)
.setComponent(new ComponentName(sourcePackageName, ACTIVITY_CLASS_TEST))
// data uri unique to each activity start to ensure actual launch and not just
// redisplay
.setData(Uri.parse("test://" + UUID.randomUUID().toString()))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
if (targetPackageName != null) {
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
}
if (targetUid > INVALID_UID) {
intent.putExtra(Intent.EXTRA_UID, targetUid);
}
if (intentExtra != null) {
if (intentExtra instanceof Intent) {
intent.putExtra(Intent.EXTRA_INTENT, intentExtra);
} else if (intentExtra instanceof PendingIntent) {
intent.putExtra(EXTRA_PENDING_INTENT, intentExtra);
} else if (intentExtra instanceof Bundle) {
intent.putExtra(EXTRA_DATA, intentExtra);
}
}
final ConditionVariable latch = new ConditionVariable();
final AtomicReference<Bundle> resultReference = new AtomicReference<>();
final RemoteCallback callback = new RemoteCallback(
bundle -> {
resultReference.set(bundle);
latch.open();
},
sResponseHandler);
intent.putExtra(EXTRA_REMOTE_CALLBACK, callback);
if (waitForReady) {
AmUtils.waitForBroadcastIdle();
startAndWaitForCommandReady(intent);
} else {
InstrumentationRegistry.getInstrumentation().getContext().startActivity(intent);
}
return () -> {
if (!latch.block(TimeUnit.SECONDS.toMillis(10))) {
throw new TimeoutException(
"Latch timed out while awiating a response from " + sourcePackageName);
}
final Bundle bundle = resultReference.get();
if (bundle != null && bundle.containsKey(EXTRA_ERROR)) {
throw (Exception) Objects.requireNonNull(bundle.getSerializable(EXTRA_ERROR));
}
return bundle;
};
}
private void startAndWaitForCommandReady(Intent intent) throws Exception {
final ConditionVariable latchForReady = new ConditionVariable();
final RemoteCallback readyCallback = new RemoteCallback(bundle -> latchForReady.open(),
sResponseHandler);
intent.putExtra(EXTRA_REMOTE_READY_CALLBACK, readyCallback);
InstrumentationRegistry.getInstrumentation().getContext().startActivity(intent);
if (!latchForReady.block(TimeUnit.SECONDS.toMillis(10))) {
throw new TimeoutException(
"Latch timed out while awiating a response from command " + intent.getAction());
}
}
private Bundle sendCommandBlocking(String sourcePackageName, @Nullable String targetPackageName,
@Nullable Parcelable intentExtra, String action)
throws Exception {
final Result result = sendCommand(sourcePackageName, targetPackageName,
/* targetUid */ INVALID_UID, intentExtra, action, /* waitForReady */ false);
return result.await();
}
private Bundle sendCommandBlocking(String sourcePackageName, int targetUid,
@Nullable Parcelable intentExtra, String action)
throws Exception {
final Result result = sendCommand(sourcePackageName, /* targetPackageName */ null,
targetUid, intentExtra, action, /* waitForReady */ false);
return result.await();
}
private Result sendCommandAndWaitForLauncherAppsCallback(String sourcePackageName,
int expectedEventCode) throws Exception {
final Bundle extra = new Bundle();
extra.putInt(EXTRA_FLAGS, expectedEventCode);
final Result result = sendCommand(sourcePackageName, /* targetPackageName */ null,
/* targetUid */ INVALID_UID, extra, ACTION_AWAIT_LAUNCHER_APPS_CALLBACK,
/* waitForReady */ true);
return result;
}
private void ensurePackageIsInstalled(String packageName, String apkPath) {
runShellCommand("pm install -R " + apkPath);
PackageInfo info = null;
try {
info = sPm.getPackageInfo(packageName, /* flags */ 0);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
Assert.assertNotNull(packageName + " should be installed", info);
}
private void ensurePackageIsNotInstalled(String packageName) {
runShellCommand("pm uninstall " + packageName);
PackageInfo info = null;
try {
info = sPm.getPackageInfo(packageName, /* flags */ 0);
} catch (PackageManager.NameNotFoundException e) {
// Expected
}
Assert.assertNull(packageName + " shouldn't be installed", info);
}
private void addPreferredActivity() {
final IntentFilter filter = new IntentFilter(
"android.intent.action.APP_ENUMERATION_PREFERRED_ACTIVITY");
final ComponentName[] candidates = {new ComponentName(TARGET_PREFERRED_ACTIVITY,
ACTIVITY_CLASS_DUMMY_ACTIVITY)};
SystemUtil.runWithShellPermissionIdentity(() -> {
sPm.addPreferredActivity(filter, IntentFilter.MATCH_ADJUSTMENT_NORMAL,
candidates, candidates[0]);
}, SET_PREFERRED_APPLICATIONS);
}
private void clearPreferredActivity() {
SystemUtil.runWithShellPermissionIdentity(() -> {
sPm.clearPackagePreferredActivities(TARGET_PREFERRED_ACTIVITY);
}, SET_PREFERRED_APPLICATIONS);
}
}