Merge changes from topic "pm_cross_user_package_visibility_6"
* changes: Using isUidPrivileged instead of getPrivateFlagsForUid API Add package manager internal api checkUidSignaturesForAllUsers Fix cross user package visibility leakage for PackageManager (6/n)
This commit is contained in:
@@ -24,6 +24,7 @@ import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.os.Binder;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
@@ -32,6 +33,7 @@ import android.util.DebugUtils;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
@@ -108,7 +110,7 @@ class BlobAccessMode {
|
||||
}
|
||||
|
||||
if ((mAccessType & ACCESS_TYPE_SAME_SIGNATURE) != 0) {
|
||||
if (checkSignatures(context, callingUid, committerUid)) {
|
||||
if (checkSignatures(callingUid, committerUid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -133,11 +135,11 @@ class BlobAccessMode {
|
||||
/**
|
||||
* Compare signatures for two packages of different users.
|
||||
*/
|
||||
private boolean checkSignatures(Context context, int uid1, int uid2) {
|
||||
private boolean checkSignatures(int uid1, int uid2) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return context.getPackageManager().checkSignatures(uid1, uid2)
|
||||
== PackageManager.SIGNATURE_MATCH;
|
||||
return LocalServices.getService(PackageManagerInternal.class)
|
||||
.checkUidSignaturesForAllUsers(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.pm.PackageManager.SignatureResult;
|
||||
import android.content.pm.SigningDetails.CertCapabilities;
|
||||
import android.content.pm.overlay.OverlayPaths;
|
||||
import android.os.Bundle;
|
||||
@@ -1283,4 +1284,15 @@ public abstract class PackageManagerInternal {
|
||||
public abstract void shutdown();
|
||||
|
||||
public abstract DynamicCodeLogger getDynamicCodeLogger();
|
||||
|
||||
/**
|
||||
* Compare the signatures of two packages that are installed in different users.
|
||||
*
|
||||
* @param uid1 First UID whose signature will be compared.
|
||||
* @param uid2 Second UID whose signature will be compared.
|
||||
* @return {@link PackageManager#SIGNATURE_MATCH} if signatures are matched.
|
||||
* @throws SecurityException if the caller does not hold the
|
||||
* {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
|
||||
*/
|
||||
public abstract @SignatureResult int checkUidSignaturesForAllUsers(int uid1, int uid2);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
import android.os.FileObserver;
|
||||
import android.os.Handler;
|
||||
@@ -129,7 +130,7 @@ public class IntentFirewall {
|
||||
mObserver.startWatching();
|
||||
}
|
||||
|
||||
private PackageManagerInternal getPackageManager() {
|
||||
PackageManagerInternal getPackageManager() {
|
||||
if (mPackageManager == null) {
|
||||
mPackageManager = LocalServices.getService(PackageManagerInternal.class);
|
||||
}
|
||||
@@ -623,12 +624,13 @@ public class IntentFirewall {
|
||||
}
|
||||
|
||||
boolean signaturesMatch(int uid1, int uid2) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
IPackageManager pm = AppGlobals.getPackageManager();
|
||||
return pm.checkUidSignatures(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
|
||||
} catch (RemoteException ex) {
|
||||
Slog.e(TAG, "Remote exception while checking signatures", ex);
|
||||
return false;
|
||||
// Compare signatures of two packages for different users.
|
||||
return getPackageManager()
|
||||
.checkUidSignaturesForAllUsers(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,11 @@
|
||||
|
||||
package com.android.server.firewall;
|
||||
|
||||
import android.app.AppGlobals;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
@@ -37,22 +34,12 @@ class SenderFilter {
|
||||
private static final String VAL_SYSTEM_OR_SIGNATURE = "system|signature";
|
||||
private static final String VAL_USER_ID = "userId";
|
||||
|
||||
static boolean isPrivilegedApp(int callerUid, int callerPid) {
|
||||
static boolean isPrivilegedApp(PackageManagerInternal pmi, int callerUid, int callerPid) {
|
||||
if (callerUid == Process.SYSTEM_UID || callerUid == 0 ||
|
||||
callerPid == Process.myPid() || callerPid == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
IPackageManager pm = AppGlobals.getPackageManager();
|
||||
try {
|
||||
return (pm.getPrivateFlagsForUid(callerUid) & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
|
||||
!= 0;
|
||||
} catch (RemoteException ex) {
|
||||
Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
|
||||
ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
return pmi.isUidPrivileged(callerUid);
|
||||
}
|
||||
|
||||
public static final FilterFactory FACTORY = new FilterFactory("sender") {
|
||||
@@ -89,7 +76,7 @@ class SenderFilter {
|
||||
@Override
|
||||
public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
|
||||
int callerUid, int callerPid, String resolvedType, int receivingUid) {
|
||||
return isPrivilegedApp(callerUid, callerPid);
|
||||
return isPrivilegedApp(ifw.getPackageManager(), callerUid, callerPid);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -97,8 +84,8 @@ class SenderFilter {
|
||||
@Override
|
||||
public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
|
||||
int callerUid, int callerPid, String resolvedType, int receivingUid) {
|
||||
return isPrivilegedApp(callerUid, callerPid) ||
|
||||
ifw.signaturesMatch(callerUid, receivingUid);
|
||||
return isPrivilegedApp(ifw.getPackageManager(), callerUid, callerPid)
|
||||
|| ifw.signaturesMatch(callerUid, receivingUid);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -228,8 +228,28 @@ public interface Computer extends PackageDataSnapshot {
|
||||
int userId);
|
||||
boolean shouldFilterApplication(@NonNull SharedUserSetting sus, int callingUid,
|
||||
int userId);
|
||||
/**
|
||||
* Different form {@link #shouldFilterApplication(PackageStateInternal, int, int)}, the function
|
||||
* returns {@code true} if the target package is not found in the device or uninstalled in the
|
||||
* current user. Unless the caller's function needs to handle the package's uninstalled state
|
||||
* by itself, using this function to keep the consistent behavior between conditions of package
|
||||
* uninstalled and visibility not allowed to avoid the side channel leakage of package
|
||||
* existence.
|
||||
* <p>
|
||||
* Package with {@link PackageManager#SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN} is not
|
||||
* treated as an uninstalled package for the carrier apps customization.
|
||||
*/
|
||||
boolean shouldFilterApplicationIncludingUninstalled(@Nullable PackageStateInternal ps,
|
||||
int callingUid, int userId);
|
||||
/**
|
||||
* Different from {@link #shouldFilterApplication(SharedUserSetting, int, int)}, the function
|
||||
* returns {@code true} if packages with the same shared user are all uninstalled in the current
|
||||
* user.
|
||||
*
|
||||
* @see #shouldFilterApplicationIncludingUninstalled(PackageStateInternal, int, int)
|
||||
*/
|
||||
boolean shouldFilterApplicationIncludingUninstalled(@NonNull SharedUserSetting sus,
|
||||
int callingUid, int userId);
|
||||
int checkUidPermission(String permName, int uid);
|
||||
int getPackageUidInternal(String packageName, long flags, int userId, int callingUid);
|
||||
long updateFlagsForApplication(long flags, int userId);
|
||||
@@ -378,6 +398,8 @@ public interface Computer extends PackageDataSnapshot {
|
||||
|
||||
int checkUidSignatures(int uid1, int uid2);
|
||||
|
||||
int checkUidSignaturesForAllUsers(int uid1, int uid2);
|
||||
|
||||
boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
|
||||
@PackageManager.CertificateInputType int type);
|
||||
|
||||
|
||||
@@ -2793,6 +2793,26 @@ public class ComputerEngine implements Computer {
|
||||
ps, callingUid, null, TYPE_UNKNOWN, userId, true /* filterUninstall */);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int, boolean)
|
||||
*/
|
||||
public final boolean shouldFilterApplicationIncludingUninstalled(
|
||||
@NonNull SharedUserSetting sus, int callingUid, int userId) {
|
||||
if (shouldFilterApplication(sus, callingUid, userId)) {
|
||||
return true;
|
||||
}
|
||||
final ArraySet<PackageStateInternal> packageStates =
|
||||
(ArraySet<PackageStateInternal>) sus.getPackageStates();
|
||||
for (int index = 0; index < packageStates.size(); index++) {
|
||||
final PackageStateInternal ps = packageStates.valueAt(index);
|
||||
if (ps.getUserStateOrDefault(userId).isInstalled() || ps.isHiddenUntilInstalled()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Filter it, all packages with the same shared uid are uninstalled.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification statuses are ordered from the worse to the best, except for
|
||||
* INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, which is the worse.
|
||||
@@ -4253,54 +4273,58 @@ public class ComputerEngine implements Computer {
|
||||
public int checkUidSignatures(int uid1, int uid2) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingUserId = UserHandle.getUserId(callingUid);
|
||||
// Map to base uids.
|
||||
final int appId1 = UserHandle.getAppId(uid1);
|
||||
final int appId2 = UserHandle.getAppId(uid2);
|
||||
SigningDetails p1SigningDetails;
|
||||
SigningDetails p2SigningDetails;
|
||||
Object obj = mSettings.getSettingBase(appId1);
|
||||
if (obj != null) {
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final SharedUserSetting sus = (SharedUserSetting) obj;
|
||||
if (shouldFilterApplication(sus, callingUid, callingUserId)) {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
p1SigningDetails = sus.signatures.mSigningDetails;
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (shouldFilterApplication(ps, callingUid, callingUserId)) {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
p1SigningDetails = ps.getSigningDetails();
|
||||
} else {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
} else {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
obj = mSettings.getSettingBase(appId2);
|
||||
if (obj != null) {
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final SharedUserSetting sus = (SharedUserSetting) obj;
|
||||
if (shouldFilterApplication(sus, callingUid, callingUserId)) {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
p2SigningDetails = sus.signatures.mSigningDetails;
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (shouldFilterApplication(ps, callingUid, callingUserId)) {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
p2SigningDetails = ps.getSigningDetails();
|
||||
} else {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
} else {
|
||||
final SigningDetails p1SigningDetails =
|
||||
getSigningDetailsAndFilterAccess(uid1, callingUid, callingUserId);
|
||||
final SigningDetails p2SigningDetails =
|
||||
getSigningDetailsAndFilterAccess(uid2, callingUid, callingUserId);
|
||||
if (p1SigningDetails == null || p2SigningDetails == null) {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
return checkSignaturesInternal(p1SigningDetails, p2SigningDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkUidSignaturesForAllUsers(int uid1, int uid2) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int userId1 = UserHandle.getUserId(uid1);
|
||||
final int userId2 = UserHandle.getUserId(uid2);
|
||||
enforceCrossUserPermission(callingUid, userId1, false /* requireFullPermission */,
|
||||
false /* checkShell */, "checkUidSignaturesForAllUsers");
|
||||
enforceCrossUserPermission(callingUid, userId2, false /* requireFullPermission */,
|
||||
false /* checkShell */, "checkUidSignaturesForAllUsers");
|
||||
final SigningDetails p1SigningDetails =
|
||||
getSigningDetailsAndFilterAccess(uid1, callingUid, userId1);
|
||||
final SigningDetails p2SigningDetails =
|
||||
getSigningDetailsAndFilterAccess(uid2, callingUid, userId2);
|
||||
if (p1SigningDetails == null || p2SigningDetails == null) {
|
||||
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
|
||||
}
|
||||
return checkSignaturesInternal(p1SigningDetails, p2SigningDetails);
|
||||
}
|
||||
|
||||
private SigningDetails getSigningDetailsAndFilterAccess(int uid, int callingUid, int userId) {
|
||||
// Map to base uids.
|
||||
final int appId = UserHandle.getAppId(uid);
|
||||
final Object obj = mSettings.getSettingBase(appId);
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final SharedUserSetting sus = (SharedUserSetting) obj;
|
||||
if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, userId)) {
|
||||
return null;
|
||||
}
|
||||
return sus.signatures.mSigningDetails;
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) {
|
||||
return null;
|
||||
}
|
||||
return ps.getSigningDetails();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int checkSignaturesInternal(SigningDetails p1SigningDetails,
|
||||
SigningDetails p2SigningDetails) {
|
||||
if (p1SigningDetails == null) {
|
||||
@@ -4363,27 +4387,9 @@ public class ComputerEngine implements Computer {
|
||||
@PackageManager.CertificateInputType int type) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int callingUserId = UserHandle.getUserId(callingUid);
|
||||
// Map to base uids.
|
||||
final int appId = UserHandle.getAppId(uid);
|
||||
final SigningDetails signingDetails;
|
||||
final Object obj = mSettings.getSettingBase(appId);
|
||||
if (obj != null) {
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final SharedUserSetting sus = (SharedUserSetting) obj;
|
||||
if (shouldFilterApplication(sus, callingUid, callingUserId)) {
|
||||
return false;
|
||||
}
|
||||
signingDetails = sus.signatures.mSigningDetails;
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (shouldFilterApplication(ps, callingUid, callingUserId)) {
|
||||
return false;
|
||||
}
|
||||
signingDetails = ps.getSigningDetails();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
final SigningDetails signingDetails =
|
||||
getSigningDetailsAndFilterAccess(uid, callingUid, callingUserId);
|
||||
if (signingDetails == null) {
|
||||
return false;
|
||||
}
|
||||
switch (type) {
|
||||
@@ -4446,13 +4452,13 @@ public class ComputerEngine implements Computer {
|
||||
final Object obj = mSettings.getSettingBase(appId);
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final SharedUserSetting sus = (SharedUserSetting) obj;
|
||||
if (shouldFilterApplication(sus, callingUid, callingUserId)) {
|
||||
if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
|
||||
return null;
|
||||
}
|
||||
return sus.name + ":" + sus.mAppId;
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (shouldFilterApplication(ps, callingUid, callingUserId)) {
|
||||
if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
|
||||
return null;
|
||||
}
|
||||
return ps.getPackageName();
|
||||
@@ -4481,14 +4487,14 @@ public class ComputerEngine implements Computer {
|
||||
final Object obj = mSettings.getSettingBase(appId);
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final SharedUserSetting sus = (SharedUserSetting) obj;
|
||||
if (shouldFilterApplication(sus, callingUid, callingUserId)) {
|
||||
if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
|
||||
names[i] = null;
|
||||
} else {
|
||||
names[i] = "shared:" + sus.name;
|
||||
}
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (shouldFilterApplication(ps, callingUid, callingUserId)) {
|
||||
if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
|
||||
names[i] = null;
|
||||
} else {
|
||||
names[i] = ps.getPackageName();
|
||||
@@ -4510,7 +4516,7 @@ public class ComputerEngine implements Computer {
|
||||
return Process.INVALID_UID;
|
||||
}
|
||||
final SharedUserSetting suid = mSettings.getSharedUserFromId(sharedUserName);
|
||||
if (suid != null && !shouldFilterApplication(suid, callingUid,
|
||||
if (suid != null && !shouldFilterApplicationIncludingUninstalled(suid, callingUid,
|
||||
UserHandle.getUserId(callingUid))) {
|
||||
return suid.mAppId;
|
||||
}
|
||||
@@ -4531,13 +4537,13 @@ public class ComputerEngine implements Computer {
|
||||
final Object obj = mSettings.getSettingBase(appId);
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final SharedUserSetting sus = (SharedUserSetting) obj;
|
||||
if (shouldFilterApplication(sus, callingUid, callingUserId)) {
|
||||
if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
|
||||
return 0;
|
||||
}
|
||||
return sus.getFlags();
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (shouldFilterApplication(ps, callingUid, callingUserId)) {
|
||||
if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
|
||||
return 0;
|
||||
}
|
||||
return ps.getFlags();
|
||||
@@ -4559,13 +4565,13 @@ public class ComputerEngine implements Computer {
|
||||
final Object obj = mSettings.getSettingBase(appId);
|
||||
if (obj instanceof SharedUserSetting) {
|
||||
final SharedUserSetting sus = (SharedUserSetting) obj;
|
||||
if (shouldFilterApplication(sus, callingUid, callingUserId)) {
|
||||
if (shouldFilterApplicationIncludingUninstalled(sus, callingUid, callingUserId)) {
|
||||
return 0;
|
||||
}
|
||||
return sus.getPrivateFlags();
|
||||
} else if (obj instanceof PackageSetting) {
|
||||
final PackageSetting ps = (PackageSetting) obj;
|
||||
if (shouldFilterApplication(ps, callingUid, callingUserId)) {
|
||||
if (shouldFilterApplicationIncludingUninstalled(ps, callingUid, callingUserId)) {
|
||||
return 0;
|
||||
}
|
||||
return ps.getPrivateFlags();
|
||||
|
||||
@@ -720,6 +720,11 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
|
||||
return snapshot().isUidPrivileged(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int checkUidSignaturesForAllUsers(int uid1, int uid2) {
|
||||
return snapshot().checkUidSignaturesForAllUsers(uid1, uid2);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
@Deprecated
|
||||
|
||||
@@ -27,6 +27,8 @@ import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.KeySet;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
@@ -56,8 +58,12 @@ public class CrossUserPackageVisibilityTests {
|
||||
private static final String TEST_DATA_DIR = "/data/local/tmp/appenumerationtests";
|
||||
private static final String CROSS_USER_TEST_PACKAGE_NAME =
|
||||
"com.android.appenumeration.crossuserpackagevisibility";
|
||||
private static final String SHARED_USER_TEST_PACKAGE_NAME =
|
||||
"com.android.appenumeration.shareduid";
|
||||
private static final File CROSS_USER_TEST_APK_FILE =
|
||||
new File(TEST_DATA_DIR, "AppEnumerationCrossUserPackageVisibilityTestApp.apk");
|
||||
private static final File SHARED_USER_TEST_APK_FILE =
|
||||
new File(TEST_DATA_DIR, "AppEnumerationSharedUserTestApp.apk");
|
||||
|
||||
@ClassRule
|
||||
@Rule
|
||||
@@ -66,6 +72,7 @@ public class CrossUserPackageVisibilityTests {
|
||||
private Instrumentation mInstrumentation;
|
||||
private IPackageManager mIPackageManager;
|
||||
private Context mContext;
|
||||
private UserReference mCurrentUser;
|
||||
private UserReference mOtherUser;
|
||||
|
||||
@Before
|
||||
@@ -77,17 +84,21 @@ public class CrossUserPackageVisibilityTests {
|
||||
// Get another user
|
||||
final UserReference primaryUser = sDeviceState.primaryUser();
|
||||
if (primaryUser.id() == UserHandle.myUserId()) {
|
||||
mCurrentUser = primaryUser;
|
||||
mOtherUser = sDeviceState.secondaryUser();
|
||||
} else {
|
||||
mCurrentUser = sDeviceState.secondaryUser();
|
||||
mOtherUser = primaryUser;
|
||||
}
|
||||
|
||||
uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
|
||||
uninstallPackage(SHARED_USER_TEST_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
uninstallPackage(CROSS_USER_TEST_PACKAGE_NAME);
|
||||
uninstallPackage(SHARED_USER_TEST_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -151,16 +162,61 @@ public class CrossUserPackageVisibilityTests {
|
||||
assertThat(e1.getMessage()).isEqualTo(e2.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFlagsForUid_cannotDetectCrossUserPkg() throws Exception {
|
||||
installPackage(CROSS_USER_TEST_APK_FILE);
|
||||
final int uid = mContext.getPackageManager().getPackageUid(
|
||||
CROSS_USER_TEST_PACKAGE_NAME, PackageManager.PackageInfoFlags.of(0));
|
||||
|
||||
uninstallPackageForUser(CROSS_USER_TEST_PACKAGE_NAME, mCurrentUser);
|
||||
|
||||
assertThat(mIPackageManager.getFlagsForUid(uid)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUidForSharedUser_cannotDetectSharedUserPkg() throws Exception {
|
||||
assertThat(mIPackageManager.getUidForSharedUser(SHARED_USER_TEST_PACKAGE_NAME))
|
||||
.isEqualTo(Process.INVALID_UID);
|
||||
|
||||
installPackageForUser(SHARED_USER_TEST_APK_FILE, mOtherUser, true /* forceQueryable */);
|
||||
|
||||
assertThat(mIPackageManager.getUidForSharedUser(SHARED_USER_TEST_PACKAGE_NAME))
|
||||
.isEqualTo(Process.INVALID_UID);
|
||||
}
|
||||
|
||||
private static void installPackage(File apk) {
|
||||
installPackageForUser(apk, null, false /* forceQueryable */);
|
||||
}
|
||||
|
||||
private static void installPackageForUser(File apk, UserReference user) {
|
||||
installPackageForUser(apk, user, false /* forceQueryable */);
|
||||
}
|
||||
|
||||
private static void installPackageForUser(File apk, UserReference user,
|
||||
boolean forceQueryable) {
|
||||
assertThat(apk.exists()).isTrue();
|
||||
final StringBuilder cmd = new StringBuilder("pm install --user ");
|
||||
cmd.append(user.id()).append(" ");
|
||||
final StringBuilder cmd = new StringBuilder("pm install -t ");
|
||||
if (forceQueryable) {
|
||||
cmd.append("--force-queryable ");
|
||||
}
|
||||
if (user != null) {
|
||||
cmd.append("--user ").append(user.id()).append(" ");
|
||||
}
|
||||
cmd.append(apk.getPath());
|
||||
final String result = runShellCommand(cmd.toString());
|
||||
assertThat(result.trim()).contains("Success");
|
||||
}
|
||||
|
||||
private static void uninstallPackage(String packageName) {
|
||||
runShellCommand("pm uninstall " + packageName);
|
||||
uninstallPackageForUser(packageName, null /* user */);
|
||||
}
|
||||
|
||||
private static void uninstallPackageForUser(String packageName, UserReference user) {
|
||||
final StringBuilder cmd = new StringBuilder("pm uninstall ");
|
||||
if (user != null) {
|
||||
cmd.append("--user ").append(user.id()).append(" ");
|
||||
}
|
||||
cmd.append(packageName);
|
||||
runShellCommand(cmd.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.appenumeration.crossuserpackagevisibility">
|
||||
<application>
|
||||
<application android:testOnly="true">
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
Reference in New Issue
Block a user