1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.restrictions; 18 19 import android.annotation.UserIdInt; 20 import android.app.AppGlobals; 21 import android.app.admin.DevicePolicyManagerInternal; 22 import android.app.admin.IDevicePolicyManager; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.IRestrictionsManager; 26 import android.content.Intent; 27 import android.content.RestrictionsManager; 28 import android.content.pm.ResolveInfo; 29 import android.os.Binder; 30 import android.os.Bundle; 31 import android.os.IUserManager; 32 import android.os.PersistableBundle; 33 import android.os.RemoteException; 34 import android.os.UserHandle; 35 import android.util.Log; 36 37 import com.android.internal.util.ArrayUtils; 38 import com.android.server.SystemService; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 43 /** 44 * SystemService wrapper for the RestrictionsManager implementation. Publishes the 45 * Context.RESTRICTIONS_SERVICE. 46 */ 47 public final class RestrictionsManagerService extends SystemService { 48 49 static final String LOG_TAG = "RestrictionsManagerService"; 50 static final boolean DEBUG = false; 51 52 private final RestrictionsManagerImpl mRestrictionsManagerImpl; 53 RestrictionsManagerService(Context context)54 public RestrictionsManagerService(Context context) { 55 super(context); 56 mRestrictionsManagerImpl = new RestrictionsManagerImpl(context); 57 } 58 59 @Override onStart()60 public void onStart() { 61 publishBinderService(Context.RESTRICTIONS_SERVICE, mRestrictionsManagerImpl); 62 } 63 64 class RestrictionsManagerImpl extends IRestrictionsManager.Stub { 65 final Context mContext; 66 private final IUserManager mUm; 67 private final IDevicePolicyManager mDpm; 68 private final DevicePolicyManagerInternal mDpmInternal; 69 RestrictionsManagerImpl(Context context)70 public RestrictionsManagerImpl(Context context) { 71 mContext = context; 72 mUm = (IUserManager) getBinderService(Context.USER_SERVICE); 73 mDpm = (IDevicePolicyManager) getBinderService(Context.DEVICE_POLICY_SERVICE); 74 mDpmInternal = getLocalService(DevicePolicyManagerInternal.class); 75 } 76 77 @Override 78 @Deprecated getApplicationRestrictions(String packageName)79 public Bundle getApplicationRestrictions(String packageName) throws RemoteException { 80 return mUm.getApplicationRestrictions(packageName); 81 } 82 83 @Override getApplicationRestrictionsPerAdminForUser( @serIdInt int userId, String packageName)84 public List<Bundle> getApplicationRestrictionsPerAdminForUser( 85 @UserIdInt int userId, String packageName) throws RemoteException { 86 if (mDpmInternal != null) { 87 return mDpmInternal.getApplicationRestrictionsPerAdminForUser(packageName, userId); 88 } 89 return new ArrayList<>(); 90 } 91 92 @Override hasRestrictionsProvider()93 public boolean hasRestrictionsProvider() throws RemoteException { 94 int userHandle = UserHandle.getCallingUserId(); 95 if (mDpm != null) { 96 final long ident = Binder.clearCallingIdentity(); 97 try { 98 return mDpm.getRestrictionsProvider(userHandle) != null; 99 } finally { 100 Binder.restoreCallingIdentity(ident); 101 } 102 } else { 103 return false; 104 } 105 } 106 107 @Override requestPermission(final String packageName, final String requestType, final String requestId, final PersistableBundle requestData)108 public void requestPermission(final String packageName, final String requestType, 109 final String requestId, 110 final PersistableBundle requestData) throws RemoteException { 111 if (DEBUG) { 112 Log.i(LOG_TAG, "requestPermission"); 113 } 114 int callingUid = Binder.getCallingUid(); 115 int userHandle = UserHandle.getUserId(callingUid); 116 if (mDpm != null) { 117 final long ident = Binder.clearCallingIdentity(); 118 try { 119 ComponentName restrictionsProvider = 120 mDpm.getRestrictionsProvider(userHandle); 121 // Check if there is a restrictions provider 122 if (restrictionsProvider == null) { 123 throw new IllegalStateException( 124 "Cannot request permission without a restrictions provider registered"); 125 } 126 // Check that the packageName matches the caller. 127 enforceCallerMatchesPackage(callingUid, packageName, "Package name does not" + 128 " match caller "); 129 // Prepare and broadcast the intent to the provider 130 Intent intent = new Intent(RestrictionsManager.ACTION_REQUEST_PERMISSION); 131 intent.setComponent(restrictionsProvider); 132 intent.putExtra(RestrictionsManager.EXTRA_PACKAGE_NAME, packageName); 133 intent.putExtra(RestrictionsManager.EXTRA_REQUEST_TYPE, requestType); 134 intent.putExtra(RestrictionsManager.EXTRA_REQUEST_ID, requestId); 135 intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, requestData); 136 mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle)); 137 } finally { 138 Binder.restoreCallingIdentity(ident); 139 } 140 } 141 } 142 143 @Override createLocalApprovalIntent()144 public Intent createLocalApprovalIntent() throws RemoteException { 145 if (DEBUG) { 146 Log.i(LOG_TAG, "requestPermission"); 147 } 148 final int userHandle = UserHandle.getCallingUserId(); 149 if (mDpm != null) { 150 final long ident = Binder.clearCallingIdentity(); 151 try { 152 ComponentName restrictionsProvider = 153 mDpm.getRestrictionsProvider(userHandle); 154 // Check if there is a restrictions provider 155 if (restrictionsProvider == null) { 156 throw new IllegalStateException( 157 "Cannot request permission without a restrictions provider registered"); 158 } 159 String providerPackageName = restrictionsProvider.getPackageName(); 160 Intent intent = new Intent(RestrictionsManager.ACTION_REQUEST_LOCAL_APPROVAL); 161 intent.setPackage(providerPackageName); 162 ResolveInfo ri = AppGlobals.getPackageManager().resolveIntent(intent, 163 null /* resolvedType */, 0 /* flags */, userHandle); 164 if (ri != null && ri.activityInfo != null && ri.activityInfo.exported) { 165 intent.setComponent(new ComponentName(ri.activityInfo.packageName, 166 ri.activityInfo.name)); 167 return intent; 168 } 169 } finally { 170 Binder.restoreCallingIdentity(ident); 171 } 172 } 173 return null; 174 } 175 176 @Override notifyPermissionResponse(String packageName, PersistableBundle response)177 public void notifyPermissionResponse(String packageName, PersistableBundle response) 178 throws RemoteException { 179 // Check caller 180 int callingUid = Binder.getCallingUid(); 181 int userHandle = UserHandle.getUserId(callingUid); 182 if (mDpm != null) { 183 final long ident = Binder.clearCallingIdentity(); 184 try { 185 ComponentName permProvider = mDpm.getRestrictionsProvider(userHandle); 186 if (permProvider == null) { 187 throw new SecurityException("No restrictions provider registered for user"); 188 } 189 enforceCallerMatchesPackage(callingUid, permProvider.getPackageName(), 190 "Restrictions provider does not match caller "); 191 192 // Post the response to target package 193 Intent responseIntent = new Intent( 194 RestrictionsManager.ACTION_PERMISSION_RESPONSE_RECEIVED); 195 responseIntent.setPackage(packageName); 196 responseIntent.putExtra(RestrictionsManager.EXTRA_RESPONSE_BUNDLE, response); 197 mContext.sendBroadcastAsUser(responseIntent, new UserHandle(userHandle)); 198 } finally { 199 Binder.restoreCallingIdentity(ident); 200 } 201 } 202 } 203 enforceCallerMatchesPackage(int callingUid, String packageName, String message)204 private void enforceCallerMatchesPackage(int callingUid, String packageName, 205 String message) { 206 try { 207 String[] pkgs = AppGlobals.getPackageManager().getPackagesForUid(callingUid); 208 if (pkgs != null) { 209 if (!ArrayUtils.contains(pkgs, packageName)) { 210 throw new SecurityException(message + callingUid); 211 } 212 } 213 } catch (RemoteException re) { 214 // Shouldn't happen 215 } 216 } 217 } 218 } 219