Merge "Relax permissions around NetworkStatsManager APIs."

This commit is contained in:
Jeff Davidson
2015-12-15 19:04:25 +00:00
committed by Android (Google) Code Review
2 changed files with 256 additions and 9 deletions

View File

@@ -0,0 +1,178 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.net;
import static org.mockito.Mockito.when;
import android.Manifest;
import android.Manifest.permission;
import android.app.AppOpsManager;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
import android.telephony.TelephonyManager;
import com.android.server.LocalServices;
import junit.framework.TestCase;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class NetworkStatsAccessTest extends TestCase {
private static final String TEST_PKG = "com.example.test";
private static final int TEST_UID = 12345;
@Mock private Context mContext;
@Mock private DevicePolicyManagerInternal mDpmi;
@Mock private TelephonyManager mTm;
@Mock private AppOpsManager mAppOps;
// Hold the real service so we can restore it when tearing down the test.
private DevicePolicyManagerInternal mSystemDpmi;
@Override
public void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
mSystemDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
LocalServices.addService(DevicePolicyManagerInternal.class, mDpmi);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTm);
when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOps);
}
@Override
public void tearDown() throws Exception {
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
LocalServices.addService(DevicePolicyManagerInternal.class, mSystemDpmi);
super.tearDown();
}
public void testCheckAccessLevel_hasCarrierPrivileges() throws Exception {
setHasCarrierPrivileges(true);
setIsDeviceOwner(false);
setIsProfileOwner(false);
setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
setHasReadHistoryPermission(false);
assertEquals(NetworkStatsAccess.Level.DEVICE,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
}
public void testCheckAccessLevel_isDeviceOwner() throws Exception {
setHasCarrierPrivileges(false);
setIsDeviceOwner(true);
setIsProfileOwner(false);
setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
setHasReadHistoryPermission(false);
assertEquals(NetworkStatsAccess.Level.DEVICE,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
}
public void testCheckAccessLevel_isProfileOwner() throws Exception {
setHasCarrierPrivileges(false);
setIsDeviceOwner(false);
setIsProfileOwner(true);
setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
setHasReadHistoryPermission(false);
assertEquals(NetworkStatsAccess.Level.USER,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
}
public void testCheckAccessLevel_hasAppOpsBitAllowed() throws Exception {
setHasCarrierPrivileges(false);
setIsDeviceOwner(false);
setIsProfileOwner(true);
setHasAppOpsPermission(AppOpsManager.MODE_ALLOWED, false);
setHasReadHistoryPermission(false);
assertEquals(NetworkStatsAccess.Level.USER,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
}
public void testCheckAccessLevel_hasAppOpsBitDefault_grantedPermission() throws Exception {
setHasCarrierPrivileges(false);
setIsDeviceOwner(false);
setIsProfileOwner(true);
setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, true);
setHasReadHistoryPermission(false);
assertEquals(NetworkStatsAccess.Level.USER,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
}
public void testCheckAccessLevel_hasReadHistoryPermission() throws Exception {
setHasCarrierPrivileges(false);
setIsDeviceOwner(false);
setIsProfileOwner(true);
setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
setHasReadHistoryPermission(true);
assertEquals(NetworkStatsAccess.Level.USER,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
}
public void testCheckAccessLevel_deniedAppOpsBit() throws Exception {
setHasCarrierPrivileges(false);
setIsDeviceOwner(false);
setIsProfileOwner(false);
setHasAppOpsPermission(AppOpsManager.MODE_ERRORED, true);
setHasReadHistoryPermission(false);
assertEquals(NetworkStatsAccess.Level.DEFAULT,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
}
public void testCheckAccessLevel_deniedAppOpsBit_deniedPermission() throws Exception {
setHasCarrierPrivileges(false);
setIsDeviceOwner(false);
setIsProfileOwner(false);
setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
setHasReadHistoryPermission(false);
assertEquals(NetworkStatsAccess.Level.DEFAULT,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
}
private void setHasCarrierPrivileges(boolean hasPrivileges) {
when(mTm.checkCarrierPrivilegesForPackage(TEST_PKG)).thenReturn(
hasPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
: TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
}
private void setIsDeviceOwner(boolean isOwner) {
when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER))
.thenReturn(isOwner);
}
private void setIsProfileOwner(boolean isOwner) {
when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER))
.thenReturn(isOwner);
}
private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
when(mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, TEST_UID, TEST_PKG))
.thenReturn(appOpsMode);
when(mContext.checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn(
hasPermission ? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED);
}
private void setHasReadHistoryPermission(boolean hasPermission) {
when(mContext.checkCallingOrSelfPermission(permission.READ_NETWORK_USAGE_HISTORY))
.thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED);
}
}

View File

@@ -16,6 +16,7 @@
package com.android.server.net;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
@@ -24,9 +25,14 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.content.res.Resources;
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.os.Process;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.frameworks.servicestests.R;
@@ -68,7 +74,7 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
// verify that history read correctly
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
636016770L, 709306L, 88038768L, 518836L);
636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
// now export into a unified format
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -77,12 +83,12 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
// clear structure completely
collection.reset();
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
0L, 0L, 0L, 0L);
0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
// and read back into structure, verifying that totals are same
collection.read(new ByteArrayInputStream(bos.toByteArray()));
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
636016770L, 709306L, 88038768L, 518836L);
636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
}
public void testReadLegacyUid() throws Exception {
@@ -94,7 +100,7 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
// verify that history read correctly
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
637076152L, 711413L, 88343717L, 521022L);
637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
// now export into a unified format
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -103,12 +109,12 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
// clear structure completely
collection.reset();
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
0L, 0L, 0L, 0L);
0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
// and read back into structure, verifying that totals are same
collection.read(new ByteArrayInputStream(bos.toByteArray()));
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
637076152L, 711413L, 88343717L, 521022L);
637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
}
public void testReadLegacyUidTags() throws Exception {
@@ -151,6 +157,66 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
}
public void testAccessLevels() throws Exception {
final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
final NetworkStats.Entry entry = new NetworkStats.Entry();
final NetworkIdentitySet identSet = new NetworkIdentitySet();
identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
TEST_IMSI, null, false));
int myUid = Process.myUid();
int otherUidInSameUser = Process.myUid() + 1;
int uidInDifferentUser = Process.myUid() + UserHandle.PER_USER_RANGE;
// Record one entry for the current UID.
entry.rxBytes = 32;
collection.recordData(identSet, myUid, SET_DEFAULT, TAG_NONE, 0, 60 * MINUTE_IN_MILLIS,
entry);
// Record one entry for another UID in this user.
entry.rxBytes = 64;
collection.recordData(identSet, otherUidInSameUser, SET_DEFAULT, TAG_NONE, 0,
60 * MINUTE_IN_MILLIS, entry);
// Record one entry for the system UID.
entry.rxBytes = 128;
collection.recordData(identSet, Process.SYSTEM_UID, SET_DEFAULT, TAG_NONE, 0,
60 * MINUTE_IN_MILLIS, entry);
// Record one entry for a UID in a different user.
entry.rxBytes = 256;
collection.recordData(identSet, uidInDifferentUser, SET_DEFAULT, TAG_NONE, 0,
60 * MINUTE_IN_MILLIS, entry);
// Verify the set of relevant UIDs for each access level.
MoreAsserts.assertEquals(new int[] { myUid },
collection.getRelevantUids(NetworkStatsAccess.Level.DEFAULT));
MoreAsserts.assertEquals(new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser },
collection.getRelevantUids(NetworkStatsAccess.Level.USER));
MoreAsserts.assertEquals(
new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser, uidInDifferentUser },
collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
// Verify security check in getHistory.
assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), myUid, SET_DEFAULT,
TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT));
try {
collection.getHistory(buildTemplateMobileAll(TEST_IMSI), otherUidInSameUser,
SET_DEFAULT, TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT);
fail("Should have thrown SecurityException for accessing different UID");
} catch (SecurityException e) {
// expected
}
// Verify appropriate aggregation in getSummary.
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32, 0, 0, 0,
NetworkStatsAccess.Level.DEFAULT);
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128, 0, 0, 0,
NetworkStatsAccess.Level.USER);
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128 + 256, 0, 0,
0, NetworkStatsAccess.Level.DEVICE);
}
/**
* Copy a {@link Resources#openRawResource(int)} into {@link File} for
* testing purposes.
@@ -170,16 +236,19 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
}
private static void assertSummaryTotal(NetworkStatsCollection collection,
NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets,
@NetworkStatsAccess.Level int accessLevel) {
final NetworkStats.Entry entry = collection.getSummary(
template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null);
template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel)
.getTotal(null);
assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
}
private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
final NetworkStats.Entry entry = collection.getSummary(
template, Long.MIN_VALUE, Long.MAX_VALUE).getTotalIncludingTags(null);
template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE)
.getTotalIncludingTags(null);
assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
}