diff options
author | Robin Lee <rgl@google.com> | 2016-07-27 14:46:13 +0100 |
---|---|---|
committer | Robin Lee <rgl@google.com> | 2016-07-28 12:45:03 +0000 |
commit | 490849b391a4dc915bc3c624e966b677663ecb77 (patch) | |
tree | fd7b46759b9345584484d6ac2b8cd5b3931b0c49 | |
parent | 0dc7a13a5e4aea5ba648d2405024239327216206 (diff) | |
download | packages_apps_Settings-490849b391a4dc915bc3c624e966b677663ecb77.tar.gz packages_apps_Settings-490849b391a4dc915bc3c624e966b677663ecb77.tar.bz2 packages_apps_Settings-490849b391a4dc915bc3c624e966b677663ecb77.zip |
VpnSettings stub unit tests
For:
- enforcing minimum target SDK
- enforcing that only actual vpn apps are shown
Bug: 30355704
Change-Id: I4fcbea8ce0d0417c089a637d999ea83299cea5d0
-rw-r--r-- | src/com/android/settings/vpn2/AppManagementFragment.java | 50 | ||||
-rw-r--r-- | tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java | 104 |
2 files changed, 131 insertions, 23 deletions
diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java index b306577f8f..d69d6193e1 100644 --- a/src/com/android/settings/vpn2/AppManagementFragment.java +++ b/src/com/android/settings/vpn2/AppManagementFragment.java @@ -15,12 +15,14 @@ */ package com.android.settings.vpn2; +import android.annotation.NonNull; import android.app.AlertDialog; import android.app.AppOpsManager; import android.app.Dialog; import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -33,12 +35,13 @@ import android.provider.Settings; import android.support.v7.preference.Preference; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.net.VpnConfig; +import com.android.internal.util.ArrayUtils; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; -import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.RestrictedPreference; @@ -57,13 +60,11 @@ public class AppManagementFragment extends SettingsPreferenceFragment private static final String KEY_ALWAYS_ON_VPN = "always_on_vpn"; private static final String KEY_FORGET_VPN = "forget_vpn"; - private AppOpsManager mAppOpsManager; private PackageManager mPackageManager; private ConnectivityManager mConnectivityManager; // VPN app info private final int mUserId = UserHandle.myUserId(); - private int mPackageUid; private String mPackageName; private PackageInfo mPackageInfo; private String mVpnLabel; @@ -105,7 +106,6 @@ public class AppManagementFragment extends SettingsPreferenceFragment addPreferencesFromResource(R.xml.vpn_app_management); mPackageManager = getContext().getPackageManager(); - mAppOpsManager = getContext().getSystemService(AppOpsManager.class); mConnectivityManager = getContext().getSystemService(ConnectivityManager.class); mPreferenceVersion = findPreference(KEY_VERSION); @@ -199,19 +199,17 @@ public class AppManagementFragment extends SettingsPreferenceFragment isEnabled ? mPackageName : null, /* lockdownEnabled */ false); } - private boolean checkTargetVersion() { - if (mPackageInfo == null || mPackageInfo.applicationInfo == null) { - return true; - } - final int targetSdk = mPackageInfo.applicationInfo.targetSdkVersion; - if (targetSdk >= Build.VERSION_CODES.N) { - return true; - } - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Package " + mPackageName + " targets SDK version " + targetSdk + "; must" - + " target at least " + Build.VERSION_CODES.N + " to use always-on."); + @VisibleForTesting + static boolean isAlwaysOnSupportedByApp(@NonNull ApplicationInfo appInfo) { + final int targetSdk = appInfo.targetSdkVersion; + if (targetSdk < Build.VERSION_CODES.N) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Package " + appInfo.packageName + " targets SDK version: " + targetSdk + + "; must target at least " + Build.VERSION_CODES.N + " to use always-on."); + } + return false; } - return false; + return true; } private void updateUI() { @@ -228,7 +226,7 @@ public class AppManagementFragment extends SettingsPreferenceFragment mPreferenceForget.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN, mUserId); - if (checkTargetVersion()) { + if (isAlwaysOnSupportedByApp(mPackageInfo.applicationInfo)) { // setSummary doesn't override the admin message when user restriction is applied mPreferenceAlwaysOn.setSummary(null); // setEnabled is not required here, as checkRestrictionAndSetDisabled @@ -266,7 +264,6 @@ public class AppManagementFragment extends SettingsPreferenceFragment } try { - mPackageUid = mPackageManager.getPackageUid(mPackageName, /* PackageInfoFlags */ 0); mPackageInfo = mPackageManager.getPackageInfo(mPackageName, /* PackageInfoFlags */ 0); mVpnLabel = VpnConfig.getVpnLabel(getPrefContext(), mPackageName).toString(); } catch (NameNotFoundException nnfe) { @@ -274,7 +271,11 @@ public class AppManagementFragment extends SettingsPreferenceFragment return false; } - if (!isVpnActivated()) { + if (mPackageInfo.applicationInfo == null) { + Log.e(TAG, "package does not include an application"); + return false; + } + if (!appHasVpnPermission(getContext(), mPackageInfo.applicationInfo)) { Log.e(TAG, "package didn't register VPN profile"); return false; } @@ -282,10 +283,13 @@ public class AppManagementFragment extends SettingsPreferenceFragment return true; } - private boolean isVpnActivated() { - final List<AppOpsManager.PackageOps> apps = mAppOpsManager.getOpsForPackage(mPackageUid, - mPackageName, new int[]{OP_ACTIVATE_VPN}); - return apps != null && apps.size() > 0 && apps.get(0) != null; + @VisibleForTesting + static boolean appHasVpnPermission(Context context, @NonNull ApplicationInfo application) { + final AppOpsManager service = + (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + final List<AppOpsManager.PackageOps> ops = service.getOpsForPackage(application.uid, + application.packageName, new int[]{OP_ACTIVATE_VPN}); + return !ArrayUtils.isEmpty(ops); } private boolean isLegacyVpnLockDownOrAnotherPackageAlwaysOn() { diff --git a/tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java b/tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java new file mode 100644 index 0000000000..fe437a6a12 --- /dev/null +++ b/tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 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.settings.vpn2; + +import static com.android.settings.vpn2.AppManagementFragment.isAlwaysOnSupportedByApp; +import static com.android.settings.vpn2.AppManagementFragment.appHasVpnPermission; +import static org.mockito.Mockito.*; + +import android.app.AppOpsManager; +import android.content.pm.ApplicationInfo; +import android.os.Build; +import android.os.Process; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.content.Context; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class AppSettingsTest extends AndroidTestCase { + private static final String TAG = AppSettingsTest.class.getSimpleName(); + + @Mock private Context mContext; + @Mock private AppOpsManager mAppOps; + + @Override + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps); + } + + @SmallTest + public void testAlwaysOnVersionRestriction() { + ApplicationInfo mockApp = createMockApp(); + + // API 23 (MNC) = not supported + mockApp.targetSdkVersion = Build.VERSION_CODES.M; + assertFalse(isAlwaysOnSupportedByApp(mockApp)); + + // API 24 (NYC) = supported + mockApp.targetSdkVersion = Build.VERSION_CODES.N; + assertTrue(isAlwaysOnSupportedByApp(mockApp)); + + // API 25 (NYC MR1) = supported + mockApp.targetSdkVersion = Build.VERSION_CODES.N_MR1; + assertTrue(isAlwaysOnSupportedByApp(mockApp)); + } + + @SmallTest + public void testAppOpsRequiredToOpenFragment() { + ApplicationInfo mockApp = createMockApp(); + + final AppOpsManager.PackageOps[] blankOps = { + new AppOpsManager.PackageOps(mockApp.packageName, mockApp.uid, new ArrayList<>()), + new AppOpsManager.PackageOps(mockApp.packageName, mockApp.uid, new ArrayList<>()) + }; + + // List with one package op + when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any())) + .thenReturn(Arrays.asList(new AppOpsManager.PackageOps[] {blankOps[0]})); + assertTrue(appHasVpnPermission(mContext, mockApp)); + + // List with more than one package op + when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any())) + .thenReturn(Arrays.asList(blankOps)); + assertTrue(appHasVpnPermission(mContext, mockApp)); + + // Empty list + when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any())) + .thenReturn(Collections.emptyList()); + assertFalse(appHasVpnPermission(mContext, mockApp)); + + // Null list (may be returned in place of an empty list) + when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any())) + .thenReturn(null); + assertFalse(appHasVpnPermission(mContext, mockApp)); + } + + private static ApplicationInfo createMockApp() { + final ApplicationInfo app = new ApplicationInfo(); + app.packageName = "com.example.mockvpn"; + app.uid = Process.FIRST_APPLICATION_UID; + return app; + } +} |