/* * Copyright (C) 2014 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.restrictions; import android.app.AppGlobals; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IRestrictionsManager; import android.content.RestrictionsManager; import android.content.pm.ResolveInfo; import android.os.Binder; import android.os.Bundle; import android.os.IUserManager; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import com.android.internal.util.ArrayUtils; import com.android.server.SystemService; /** * SystemService wrapper for the RestrictionsManager implementation. Publishes the * Context.RESTRICTIONS_SERVICE. */ public final class RestrictionsManagerService extends SystemService { static final String LOG_TAG = "RestrictionsManagerService"; static final boolean DEBUG = false; private final RestrictionsManagerImpl mRestrictionsManagerImpl; public RestrictionsManagerService(Context context) { super(context); mRestrictionsManagerImpl = new RestrictionsManagerImpl(context); } @Override public void onStart() { publishBinderService(Context.RESTRICTIONS_SERVICE, mRestrictionsManagerImpl); } class RestrictionsManagerImpl extends IRestrictionsManager.Stub { final Context mContext; private final IUserManager mUm; private final IDevicePolicyManager mDpm; public RestrictionsManagerImpl(Context context) { mContext = context; mUm = (IUserManager) getBinderService(Context.USER_SERVICE); mDpm = (IDevicePolicyManager) getBinderService(Context.DEVICE_POLICY_SERVICE); } @Override public Bundle getApplicationRestrictions(String packageName) throws RemoteException { return mUm.getApplicationRestrictions(packageName); } @Override public boolean hasRestrictionsProvider() throws RemoteException { int userHandle = UserHandle.getCallingUserId(); if (mDpm != null) { long ident = Binder.clearCallingIdentity(); try { return mDpm.getRestrictionsProvider(userHandle) != null; } finally { Binder.restoreCallingIdentity(ident); } } else { return false; } } @Override public void requestPermission(final String packageName, final String requestType, final String requestId, final PersistableBundle requestData) throws RemoteException { if (DEBUG) { Log.i(LOG_TAG, "requestPermission"); } int callingUid = Binder.getCallingUid(); int userHandle = UserHandle.getUserId(callingUid); if (mDpm != null) { long ident = Binder.clearCallingIdentity(); try { ComponentName restrictionsProvider = mDpm.getRestrictionsProvider(userHandle); // Check if there is a restrictions provider if (restrictionsProvider == null) { throw new IllegalStateException( "Cannot request permission without a restrictions provider registered"); } // Check that the packageName matches the caller. enforceCallerMatchesPackage(callingUid, packageName, "Package name does not" + " match caller "); // Prepare and broadcast the intent to the provider Intent intent = new Intent(RestrictionsManager.ACTION_REQUEST_PERMISSION); intent.setComponent(restrictionsProvider); intent.putExtra(RestrictionsManager.EXTRA_PACKAGE_NAME, packageName); intent.putExtra(RestrictionsManager.EXTRA_REQUEST_TYPE, requestType); intent.putExtra(RestrictionsManager.EXTRA_REQUEST_ID, requestId); intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, requestData); mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle)); } finally { Binder.restoreCallingIdentity(ident); } } } @Override public Intent createLocalApprovalIntent() throws RemoteException { if (DEBUG) { Log.i(LOG_TAG, "requestPermission"); } final int userHandle = UserHandle.getCallingUserId(); if (mDpm != null) { long ident = Binder.clearCallingIdentity(); try { ComponentName restrictionsProvider = mDpm.getRestrictionsProvider(userHandle); // Check if there is a restrictions provider if (restrictionsProvider == null) { throw new IllegalStateException( "Cannot request permission without a restrictions provider registered"); } String providerPackageName = restrictionsProvider.getPackageName(); Intent intent = new Intent(RestrictionsManager.ACTION_REQUEST_LOCAL_APPROVAL); intent.setPackage(providerPackageName); ResolveInfo ri = AppGlobals.getPackageManager().resolveIntent(intent, null /* resolvedType */, 0 /* flags */, userHandle); if (ri != null && ri.activityInfo != null && ri.activityInfo.exported) { intent.setComponent(new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name)); return intent; } } finally { Binder.restoreCallingIdentity(ident); } } return null; } @Override public void notifyPermissionResponse(String packageName, PersistableBundle response) throws RemoteException { // Check caller int callingUid = Binder.getCallingUid(); int userHandle = UserHandle.getUserId(callingUid); if (mDpm != null) { long ident = Binder.clearCallingIdentity(); try { ComponentName permProvider = mDpm.getRestrictionsProvider(userHandle); if (permProvider == null) { throw new SecurityException("No restrictions provider registered for user"); } enforceCallerMatchesPackage(callingUid, permProvider.getPackageName(), "Restrictions provider does not match caller "); // Post the response to target package Intent responseIntent = new Intent( RestrictionsManager.ACTION_PERMISSION_RESPONSE_RECEIVED); responseIntent.setPackage(packageName); responseIntent.putExtra(RestrictionsManager.EXTRA_RESPONSE_BUNDLE, response); mContext.sendBroadcastAsUser(responseIntent, new UserHandle(userHandle)); } finally { Binder.restoreCallingIdentity(ident); } } } private void enforceCallerMatchesPackage(int callingUid, String packageName, String message) { try { String[] pkgs = AppGlobals.getPackageManager().getPackagesForUid(callingUid); if (pkgs != null) { if (!ArrayUtils.contains(pkgs, packageName)) { throw new SecurityException(message + callingUid); } } } catch (RemoteException re) { // Shouldn't happen } } } }