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