Merge "Relax permissions around NetworkStatsManager APIs."
This commit is contained in:
committed by
Android (Google) Code Review
commit
7c16024c83
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user