diff --git a/src/com/android/settings/applications/AppCounter.java b/src/com/android/settings/applications/AppCounter.java index 8758b1453bb..8eff5263e17 100644 --- a/src/com/android/settings/applications/AppCounter.java +++ b/src/com/android/settings/applications/AppCounter.java @@ -32,7 +32,7 @@ public abstract class AppCounter extends AsyncTask { public AppCounter(Context context, PackageManagerWrapper packageManager) { mPm = packageManager; - mUm = UserManager.get(context); + mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); } @Override diff --git a/src/com/android/settings/applications/AppStateAppOpsBridge.java b/src/com/android/settings/applications/AppStateAppOpsBridge.java index cfbb2fcfc8f..420d955462e 100644 --- a/src/com/android/settings/applications/AppStateAppOpsBridge.java +++ b/src/com/android/settings/applications/AppStateAppOpsBridge.java @@ -19,12 +19,12 @@ import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManager.PackageOps; import android.content.Context; -import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.support.annotation.VisibleForTesting; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; @@ -46,7 +46,7 @@ public abstract class AppStateAppOpsBridge extends AppStateBaseBridge { private static final String TAG = "AppStateAppOpsBridge"; - private final IPackageManager mIPackageManager; + private final IPackageManagerWrapper mIPackageManager; private final UserManager mUserManager; private final List mProfiles; private final AppOpsManager mAppOpsManager; @@ -56,9 +56,16 @@ public abstract class AppStateAppOpsBridge extends AppStateBaseBridge { public AppStateAppOpsBridge(Context context, ApplicationsState appState, Callback callback, int appOpsOpCode, String[] permissions) { + this(context, appState, callback, appOpsOpCode, permissions, + new IPackageManagerWrapperImpl(AppGlobals.getPackageManager())); + } + + @VisibleForTesting(otherwise = VisibleForTesting.NONE) + AppStateAppOpsBridge(Context context, ApplicationsState appState, Callback callback, + int appOpsOpCode, String[] permissions, IPackageManagerWrapper packageManager) { super(appState, callback); mContext = context; - mIPackageManager = AppGlobals.getPackageManager(); + mIPackageManager = packageManager; mUserManager = UserManager.get(context); mProfiles = mUserManager.getUserProfiles(); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); @@ -92,18 +99,21 @@ public abstract class AppStateAppOpsBridge extends AppStateBaseBridge { .getUserId(uid))); try { permissionState.packageInfo = mIPackageManager.getPackageInfo(pkg, - PackageManager.GET_PERMISSIONS | PackageManager.MATCH_UNINSTALLED_PACKAGES, + PackageManager.GET_PERMISSIONS | PackageManager.MATCH_ANY_USER, permissionState.userHandle.getIdentifier()); - // Check static permission state (whatever that is declared in package manifest) - String[] requestedPermissions = permissionState.packageInfo.requestedPermissions; - int[] permissionFlags = permissionState.packageInfo.requestedPermissionsFlags; - if (requestedPermissions != null) { - for (int i = 0; i < requestedPermissions.length; i++) { - if (doesAnyPermissionMatch(requestedPermissions[i], mPermissions)) { - permissionState.permissionDeclared = true; - if ((permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) { - permissionState.staticPermissionGranted = true; - break; + if (permissionState.packageInfo != null) { + // Check static permission state (whatever that is declared in package manifest) + String[] requestedPermissions = permissionState.packageInfo.requestedPermissions; + int[] permissionFlags = permissionState.packageInfo.requestedPermissionsFlags; + if (requestedPermissions != null) { + for (int i = 0; i < requestedPermissions.length; i++) { + if (doesAnyPermissionMatch(requestedPermissions[i], mPermissions)) { + permissionState.permissionDeclared = true; + if ((permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) + != 0) { + permissionState.staticPermissionGranted = true; + break; + } } } } diff --git a/src/com/android/settings/applications/IPackageManagerWrapper.java b/src/com/android/settings/applications/IPackageManagerWrapper.java index f88598527e3..b4d1b85e8f7 100644 --- a/src/com/android/settings/applications/IPackageManagerWrapper.java +++ b/src/com/android/settings/applications/IPackageManagerWrapper.java @@ -17,6 +17,8 @@ package com.android.settings.applications; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.os.RemoteException; @@ -41,4 +43,33 @@ public interface IPackageManagerWrapper { * @see android.content.pm.IPackageManager#findPersistentPreferredActivity */ ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) throws RemoteException; + + /** + * Calls {@code IPackageManager.getPackageInfo()}. + * + * @see android.content.pm.IPackageManager#getPackageInfo + */ + PackageInfo getPackageInfo(String packageName, int flags, int userId) throws RemoteException; + + /** + * Calls {@code IPackageManager.getAppOpPermissionPackages()}. + * + * @see android.content.pm.IPackageManager#getAppOpPermissionPackages + */ + String[] getAppOpPermissionPackages(String permissionName) throws RemoteException; + + /** + * Calls {@code IPackageManager.isPackageAvailable()}. + * + * @see android.content.pm.IPackageManager#isPackageAvailable + */ + boolean isPackageAvailable(String packageName, int userId) throws RemoteException; + + /** + * Calls {@code IPackageManager.getPackagesHoldingPermissions()}. + * + * @see android.content.pm.IPackageManager#getPackagesHoldingPermissions + */ + ParceledListSlice getPackagesHoldingPermissions( + String[] permissions, int flags, int userId) throws RemoteException; } diff --git a/src/com/android/settings/applications/IPackageManagerWrapperImpl.java b/src/com/android/settings/applications/IPackageManagerWrapperImpl.java index 5ea15b9ad64..af5f37868d9 100644 --- a/src/com/android/settings/applications/IPackageManagerWrapperImpl.java +++ b/src/com/android/settings/applications/IPackageManagerWrapperImpl.java @@ -18,6 +18,8 @@ package com.android.settings.applications; import android.content.Intent; import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.os.RemoteException; @@ -39,4 +41,27 @@ public class IPackageManagerWrapperImpl implements IPackageManagerWrapper { throws RemoteException { return mPms.findPersistentPreferredActivity(intent, userId); } + + @Override + public PackageInfo getPackageInfo(String packageName, int flags, int userId) + throws RemoteException { + return mPms.getPackageInfo(packageName, flags, userId); + } + + @Override + public String[] getAppOpPermissionPackages(String permissionName) throws RemoteException { + return mPms.getAppOpPermissionPackages(permissionName); + } + + @Override + public boolean isPackageAvailable(String packageName, int userId) throws RemoteException { + return mPms.isPackageAvailable(packageName, userId); + } + + @Override + public ParceledListSlice getPackagesHoldingPermissions( + String[] permissions, int flags, int userId) throws RemoteException { + return mPms.getPackagesHoldingPermissions(permissions, flags, userId); + } + } diff --git a/src/com/android/settings/applications/RunningState.java b/src/com/android/settings/applications/RunningState.java index dd44887ae10..d4abe6c4e28 100644 --- a/src/com/android/settings/applications/RunningState.java +++ b/src/com/android/settings/applications/RunningState.java @@ -500,7 +500,7 @@ public class RunningState { si.mRunningService = service; try { si.mServiceInfo = ActivityThread.getPackageManager().getServiceInfo( - service.service, PackageManager.MATCH_UNINSTALLED_PACKAGES, + service.service, PackageManager.MATCH_ANY_USER, UserHandle.getUserId(service.uid)); if (si.mServiceInfo == null) { diff --git a/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java b/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java index 6c23b395b72..69f174b2a27 100644 --- a/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java +++ b/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java @@ -144,7 +144,7 @@ public class SharedPreferencesLogger implements SharedPreferences { } catch (Exception e) { } try { - pm.getPackageInfo(value, PackageManager.MATCH_UNINSTALLED_PACKAGES); + pm.getPackageInfo(value, PackageManager.MATCH_ANY_USER); logPackageName(key, value); } catch (PackageManager.NameNotFoundException e) { // Clearly not a package, and it's unlikely this preference is in prefSet, so diff --git a/tests/robotests/src/com/android/settings/applications/AppStateAppOpsBridgeTest.java b/tests/robotests/src/com/android/settings/applications/AppStateAppOpsBridgeTest.java new file mode 100644 index 00000000000..f17509a72b9 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/AppStateAppOpsBridgeTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2017 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.applications; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.app.AppOpsManager; +import android.content.Context; +import android.os.RemoteException; +import android.os.UserManager; +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public final class AppStateAppOpsBridgeTest { + + @Mock private Context mContext; + @Mock private UserManager mUserManager; + @Mock private IPackageManagerWrapper mPackageManagerService; + @Mock private AppOpsManager mAppOpsManager; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager); + } + + @Test + public void getPermissionInfo_nullPackageInfo_shouldNotCrash() throws RemoteException { + when(mPackageManagerService.getPackageInfo(anyString(), anyInt(), anyInt())) + .thenReturn(null); + TestAppStateAppOpsBridge appStateAppOpsBridge = new TestAppStateAppOpsBridge(); + + appStateAppOpsBridge.getPermissionInfo("pkg1", 1); + // should not crash + } + + private class TestAppStateAppOpsBridge extends AppStateAppOpsBridge { + public TestAppStateAppOpsBridge() { + super(mContext, null, null, AppOpsManager.OP_SYSTEM_ALERT_WINDOW, + new String[] {Manifest.permission.SYSTEM_ALERT_WINDOW}, + mPackageManagerService); + } + + @Override + protected void updateExtraInfo(AppEntry app, String pkg, int uid) { + } + } +}