Merge "Support backward compatibility for restricted network permission" am: 3e8de1cade

am: 5d443532b6

Change-Id: I9b2faf60ff007e2cc08dacd6988fe98377468e7e
This commit is contained in:
Paul Hu
2018-11-01 00:46:15 -07:00
committed by android-build-merger
2 changed files with 78 additions and 54 deletions

View File

@@ -23,6 +23,8 @@ import static android.Manifest.permission.NETWORK_STACK;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -64,6 +66,7 @@ public class PermissionMonitor {
private static final boolean DBG = true; private static final boolean DBG = true;
private static final Boolean SYSTEM = Boolean.TRUE; private static final Boolean SYSTEM = Boolean.TRUE;
private static final Boolean NETWORK = Boolean.FALSE; private static final Boolean NETWORK = Boolean.FALSE;
private static final int VERSION_Q = Build.VERSION_CODES.Q;
private final Context mContext; private final Context mContext;
private final PackageManager mPackageManager; private final PackageManager mPackageManager;
@@ -87,7 +90,7 @@ public class PermissionMonitor {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); String action = intent.getAction();
int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
int appUid = intent.getIntExtra(Intent.EXTRA_UID, -1); int appUid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
Uri appData = intent.getData(); Uri appData = intent.getData();
String appName = appData != null ? appData.getSchemeSpecificPart() : null; String appName = appData != null ? appData.getSchemeSpecificPart() : null;
@@ -127,7 +130,7 @@ public class PermissionMonitor {
} }
for (PackageInfo app : apps) { for (PackageInfo app : apps) {
int uid = app.applicationInfo != null ? app.applicationInfo.uid : -1; int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
if (uid < 0) { if (uid < 0) {
continue; continue;
} }
@@ -161,6 +164,11 @@ public class PermissionMonitor {
return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct(); return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
} }
@VisibleForTesting
int getDeviceFirstSdkInt() {
return Build.VERSION.FIRST_SDK_INT;
}
@VisibleForTesting @VisibleForTesting
boolean hasPermission(PackageInfo app, String permission) { boolean hasPermission(PackageInfo app, String permission) {
if (app.requestedPermissions != null) { if (app.requestedPermissions != null) {
@@ -180,11 +188,18 @@ public class PermissionMonitor {
private boolean hasRestrictedNetworkPermission(PackageInfo app) { private boolean hasRestrictedNetworkPermission(PackageInfo app) {
// TODO : remove this check in the future(b/31479477). All apps should just // TODO : remove this check in the future(b/31479477). All apps should just
// request the appropriate permission for their use case since android Q. // request the appropriate permission for their use case since android Q.
if (app.applicationInfo != null if (app.applicationInfo != null) {
&& app.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q // Backward compatibility for b/114245686, on devices that launched before Q daemons
// and apps running as the system UID are exempted from this check.
if (app.applicationInfo.uid == SYSTEM_UID && getDeviceFirstSdkInt() < VERSION_Q) {
return true;
}
if (app.applicationInfo.targetSdkVersion < VERSION_Q
&& isVendorApp(app.applicationInfo)) { && isVendorApp(app.applicationInfo)) {
return true; return true;
} }
}
return hasPermission(app, CONNECTIVITY_INTERNAL) return hasPermission(app, CONNECTIVITY_INTERNAL)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS); || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
} }

View File

@@ -25,6 +25,7 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.os.Process.SYSTEM_UID;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -55,26 +56,41 @@ public class PermissionMonitorTest {
private static final String PARTITION_OEM = "oem"; private static final String PARTITION_OEM = "oem";
private static final String PARTITION_PRODUCT = "product"; private static final String PARTITION_PRODUCT = "product";
private static final String PARTITION_VENDOR = "vendor"; private static final String PARTITION_VENDOR = "vendor";
private static final int VERSION_P = Build.VERSION_CODES.P;
private static final int VERSION_Q = Build.VERSION_CODES.Q;
@Mock private Context mContext; @Mock private Context mContext;
@Mock private PackageManager mPackageManager; @Mock private PackageManager mPackageManager;
private PermissionMonitor mPermissionMonitor; private PermissionMonitor mPermissionMonitor;
private int mMockFirstSdkInt;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getPackagesForUid(MOCK_UID)).thenReturn(MOCK_PACKAGE_NAMES); when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(MOCK_PACKAGE_NAMES);
mPermissionMonitor = new PermissionMonitor(mContext, null); // Try to use spy() here for stubbing getDeviceFirstSdkInt value but the spies are loaded
// by a custom class loader that's different from the loader used for loading the real
// thing. That means those two classes are not in the same package, so a package private
// method is not accessible. Hence, using override method to control FIRST_SDK_INT value
// instead of spy function for testing.
mPermissionMonitor = new PermissionMonitor(mContext, null) {
@Override
int getDeviceFirstSdkInt() {
return mMockFirstSdkInt;
}
};
} }
private void expectPermission(String[] permissions, String partition, private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
int targetSdkVersion) throws Exception { String... permission) throws Exception {
final PackageInfo packageInfo = packageInfoWithPermissions(permissions, partition); final PackageInfo packageInfo = packageInfoWithPermissions(permission, partition);
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion; packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
packageInfo.applicationInfo.uid = uid;
when(mPackageManager.getPackageInfoAsUser( when(mPackageManager.getPackageInfoAsUser(
eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo); eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
} }
private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) { private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
@@ -136,51 +152,44 @@ public class PermissionMonitorTest {
@Test @Test
public void testHasUseBackgroundNetworksPermission() throws Exception { public void testHasUseBackgroundNetworksPermission() throws Exception {
expectPermission(new String[] { CHANGE_NETWORK_STATE }, assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID));
PARTITION_SYSTEM, Build.VERSION_CODES.P); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CHANGE_NETWORK_STATE));
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, NETWORK_STACK));
expectPermission(new String[] { NETWORK_STACK }, PARTITION_SYSTEM, Build.VERSION_CODES.P); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CONNECTIVITY_INTERNAL));
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID,
expectPermission(new String[] { CONNECTIVITY_INTERNAL }, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
PARTITION_SYSTEM, Build.VERSION_CODES.P); assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CHANGE_WIFI_STATE));
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CONNECTIVITY_USE_RESTRICTED_NETWORKS },
PARTITION_SYSTEM, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CHANGE_NETWORK_STATE }, assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID));
PARTITION_VENDOR, Build.VERSION_CODES.P); assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID, CHANGE_WIFI_STATE));
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); }
expectPermission(new String[] { NETWORK_STACK },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CONNECTIVITY_INTERNAL },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CONNECTIVITY_USE_RESTRICTED_NETWORKS },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.P); @Test
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); public void testHasUseBackgroundNetworksPermissionSystemUid() throws Exception {
expectPermission(new String[] { CHANGE_WIFI_STATE }, mMockFirstSdkInt = VERSION_P;
PARTITION_SYSTEM, Build.VERSION_CODES.P); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
expectPermission(new String[] {}, PARTITION_VENDOR, Build.VERSION_CODES.P); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID,
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); CONNECTIVITY_USE_RESTRICTED_NETWORKS));
expectPermission(new String[] { CHANGE_WIFI_STATE },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.Q); mMockFirstSdkInt = VERSION_Q;
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
expectPermission(new String[] { CHANGE_WIFI_STATE }, assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
PARTITION_SYSTEM, Build.VERSION_CODES.Q); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID,
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); CONNECTIVITY_USE_RESTRICTED_NETWORKS));
expectPermission(new String[] {}, PARTITION_VENDOR, Build.VERSION_CODES.Q); }
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CHANGE_WIFI_STATE }, @Test
PARTITION_VENDOR, Build.VERSION_CODES.Q); public void testHasUseBackgroundNetworksPermissionVendorApp() throws Exception {
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID));
assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CHANGE_NETWORK_STATE));
assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, NETWORK_STACK));
assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CONNECTIVITY_INTERNAL));
assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID,
CONNECTIVITY_USE_RESTRICTED_NETWORKS));
assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CHANGE_WIFI_STATE));
assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID));
assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID, CHANGE_WIFI_STATE));
} }
} }