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.app.AppGlobals;
20 import android.app.admin.IDevicePolicyManager;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IRestrictionsManager;
25 import android.content.RestrictionsManager;
26 import android.content.pm.ResolveInfo;
27 import android.os.Binder;
28 import android.os.Bundle;
29 import android.os.IUserManager;
30 import android.os.PersistableBundle;
31 import android.os.RemoteException;
32 import android.os.UserHandle;
33 import android.util.Log;
34 
35 import com.android.internal.util.ArrayUtils;
36 import com.android.server.SystemService;
37 
38 /**
39  * SystemService wrapper for the RestrictionsManager implementation. Publishes the
40  * Context.RESTRICTIONS_SERVICE.
41  */
42 public final class RestrictionsManagerService extends SystemService {
43 
44     static final String LOG_TAG = "RestrictionsManagerService";
45     static final boolean DEBUG = false;
46 
47     private final RestrictionsManagerImpl mRestrictionsManagerImpl;
48 
RestrictionsManagerService(Context context)49     public RestrictionsManagerService(Context context) {
50         super(context);
51         mRestrictionsManagerImpl = new RestrictionsManagerImpl(context);
52     }
53 
54     @Override
onStart()55     public void onStart() {
56         publishBinderService(Context.RESTRICTIONS_SERVICE, mRestrictionsManagerImpl);
57     }
58 
59     class RestrictionsManagerImpl extends IRestrictionsManager.Stub {
60         final Context mContext;
61         private final IUserManager mUm;
62         private final IDevicePolicyManager mDpm;
63 
RestrictionsManagerImpl(Context context)64         public RestrictionsManagerImpl(Context context) {
65             mContext = context;
66             mUm = (IUserManager) getBinderService(Context.USER_SERVICE);
67             mDpm = (IDevicePolicyManager) getBinderService(Context.DEVICE_POLICY_SERVICE);
68         }
69 
70         @Override
getApplicationRestrictions(String packageName)71         public Bundle getApplicationRestrictions(String packageName) throws RemoteException {
72             return mUm.getApplicationRestrictions(packageName);
73         }
74 
75         @Override
hasRestrictionsProvider()76         public boolean hasRestrictionsProvider() throws RemoteException {
77             int userHandle = UserHandle.getCallingUserId();
78             if (mDpm != null) {
79                 final long ident = Binder.clearCallingIdentity();
80                 try {
81                     return mDpm.getRestrictionsProvider(userHandle) != null;
82                 } finally {
83                     Binder.restoreCallingIdentity(ident);
84                 }
85             } else {
86                 return false;
87             }
88         }
89 
90         @Override
requestPermission(final String packageName, final String requestType, final String requestId, final PersistableBundle requestData)91         public void requestPermission(final String packageName, final String requestType,
92                 final String requestId,
93                 final PersistableBundle requestData) throws RemoteException {
94             if (DEBUG) {
95                 Log.i(LOG_TAG, "requestPermission");
96             }
97             int callingUid = Binder.getCallingUid();
98             int userHandle = UserHandle.getUserId(callingUid);
99             if (mDpm != null) {
100                 final long ident = Binder.clearCallingIdentity();
101                 try {
102                     ComponentName restrictionsProvider =
103                             mDpm.getRestrictionsProvider(userHandle);
104                     // Check if there is a restrictions provider
105                     if (restrictionsProvider == null) {
106                         throw new IllegalStateException(
107                             "Cannot request permission without a restrictions provider registered");
108                     }
109                     // Check that the packageName matches the caller.
110                     enforceCallerMatchesPackage(callingUid, packageName, "Package name does not" +
111                             " match caller ");
112                     // Prepare and broadcast the intent to the provider
113                     Intent intent = new Intent(RestrictionsManager.ACTION_REQUEST_PERMISSION);
114                     intent.setComponent(restrictionsProvider);
115                     intent.putExtra(RestrictionsManager.EXTRA_PACKAGE_NAME, packageName);
116                     intent.putExtra(RestrictionsManager.EXTRA_REQUEST_TYPE, requestType);
117                     intent.putExtra(RestrictionsManager.EXTRA_REQUEST_ID, requestId);
118                     intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, requestData);
119                     mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
120                 } finally {
121                     Binder.restoreCallingIdentity(ident);
122                 }
123             }
124         }
125 
126         @Override
createLocalApprovalIntent()127         public Intent createLocalApprovalIntent() throws RemoteException {
128             if (DEBUG) {
129                 Log.i(LOG_TAG, "requestPermission");
130             }
131             final int userHandle = UserHandle.getCallingUserId();
132             if (mDpm != null) {
133                 final long ident = Binder.clearCallingIdentity();
134                 try {
135                     ComponentName restrictionsProvider =
136                             mDpm.getRestrictionsProvider(userHandle);
137                     // Check if there is a restrictions provider
138                     if (restrictionsProvider == null) {
139                         throw new IllegalStateException(
140                             "Cannot request permission without a restrictions provider registered");
141                     }
142                     String providerPackageName = restrictionsProvider.getPackageName();
143                     Intent intent = new Intent(RestrictionsManager.ACTION_REQUEST_LOCAL_APPROVAL);
144                     intent.setPackage(providerPackageName);
145                     ResolveInfo ri = AppGlobals.getPackageManager().resolveIntent(intent,
146                             null /* resolvedType */, 0 /* flags */, userHandle);
147                     if (ri != null && ri.activityInfo != null && ri.activityInfo.exported) {
148                         intent.setComponent(new ComponentName(ri.activityInfo.packageName,
149                                 ri.activityInfo.name));
150                         return intent;
151                     }
152                 } finally {
153                     Binder.restoreCallingIdentity(ident);
154                 }
155             }
156             return null;
157         }
158 
159         @Override
notifyPermissionResponse(String packageName, PersistableBundle response)160         public void notifyPermissionResponse(String packageName, PersistableBundle response)
161                 throws RemoteException {
162             // Check caller
163             int callingUid = Binder.getCallingUid();
164             int userHandle = UserHandle.getUserId(callingUid);
165             if (mDpm != null) {
166                 final long ident = Binder.clearCallingIdentity();
167                 try {
168                     ComponentName permProvider = mDpm.getRestrictionsProvider(userHandle);
169                     if (permProvider == null) {
170                         throw new SecurityException("No restrictions provider registered for user");
171                     }
172                     enforceCallerMatchesPackage(callingUid, permProvider.getPackageName(),
173                             "Restrictions provider does not match caller ");
174 
175                     // Post the response to target package
176                     Intent responseIntent = new Intent(
177                             RestrictionsManager.ACTION_PERMISSION_RESPONSE_RECEIVED);
178                     responseIntent.setPackage(packageName);
179                     responseIntent.putExtra(RestrictionsManager.EXTRA_RESPONSE_BUNDLE, response);
180                     mContext.sendBroadcastAsUser(responseIntent, new UserHandle(userHandle));
181                 } finally {
182                     Binder.restoreCallingIdentity(ident);
183                 }
184             }
185         }
186 
enforceCallerMatchesPackage(int callingUid, String packageName, String message)187         private void enforceCallerMatchesPackage(int callingUid, String packageName,
188                 String message) {
189             try {
190                 String[] pkgs = AppGlobals.getPackageManager().getPackagesForUid(callingUid);
191                 if (pkgs != null) {
192                     if (!ArrayUtils.contains(pkgs, packageName)) {
193                         throw new SecurityException(message + callingUid);
194                     }
195                 }
196             } catch (RemoteException re) {
197                 // Shouldn't happen
198             }
199         }
200     }
201 }
202