diff options
Diffstat (limited to 'services')
5 files changed, 230 insertions, 0 deletions
diff --git a/services/Android.mk b/services/Android.mk index 5fcef64cb963..b4de9038fe6e 100644 --- a/services/Android.mk +++ b/services/Android.mk @@ -25,6 +25,7 @@ services := \ backup \ devicepolicy \ print \ + restrictions \ usb \ voiceinteraction diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d78fb13f4186..a52396e316df 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -130,6 +130,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final boolean DBG = false; + private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; + final Context mContext; final UserManager mUserManager; final PowerManager.WakeLock mWakeLock; @@ -190,6 +192,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // This is the list of component allowed to start lock task mode. final List<ComponentName> mLockTaskComponents = new ArrayList<ComponentName>(); + ComponentName mRestrictionsProvider; + public DevicePolicyData(int userHandle) { mUserHandle = userHandle; } @@ -944,6 +948,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.startDocument(null, true); out.startTag(null, "policies"); + if (policy.mRestrictionsProvider != null) { + out.attribute(null, ATTR_PERMISSION_PROVIDER, + policy.mRestrictionsProvider.flattenToString()); + } final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { @@ -1039,6 +1047,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new XmlPullParserException( "Settings do not start with policies tag: found " + tag); } + + // Extract the permission provider component name if available + String permissionProvider = parser.getAttributeValue(null, ATTR_PERMISSION_PROVIDER); + if (permissionProvider != null) { + policy.mRestrictionsProvider = ComponentName.unflattenFromString(permissionProvider); + } + type = parser.next(); int outerDepth = parser.getDepth(); policy.mLockTaskComponents.clear(); @@ -3303,6 +3318,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) { + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + int userHandle = UserHandle.getCallingUserId(); + DevicePolicyData userData = getUserData(userHandle); + userData.mRestrictionsProvider = permissionProvider; + saveSettingsLocked(userHandle); + } + } + + @Override + public ComponentName getRestrictionsProvider(int userHandle) { + synchronized (this) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Only the system can query the permission provider"); + } + DevicePolicyData userData = getUserData(userHandle); + return userData != null ? userData.mRestrictionsProvider : null; + } + } + public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) { int callingUserId = UserHandle.getCallingUserId(); synchronized (this) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index c0f60c74296f..27098e7ae08d 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -80,6 +80,7 @@ import com.android.server.pm.PackageManagerService; import com.android.server.pm.UserManagerService; import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; +import com.android.server.restrictions.RestrictionsManagerService; import com.android.server.search.SearchManagerService; import com.android.server.statusbar.StatusBarManagerService; import com.android.server.storage.DeviceStorageMonitorService; @@ -941,6 +942,12 @@ public final class SystemServer { } try { + mSystemServiceManager.startService(RestrictionsManagerService.class); + } catch (Throwable e) { + reportWtf("starting RestrictionsManagerService", e); + } + + try { mSystemServiceManager.startService(MediaSessionService.class); } catch (Throwable e) { reportWtf("starting MediaSessionService", e); diff --git a/services/restrictions/Android.mk b/services/restrictions/Android.mk new file mode 100644 index 000000000000..fcf8626af5fd --- /dev/null +++ b/services/restrictions/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := services.restrictions + +LOCAL_SRC_FILES += \ + $(call all-java-files-under,java) + +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java new file mode 100644 index 000000000000..e1f77b3a68b1 --- /dev/null +++ b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java @@ -0,0 +1,171 @@ +/* + * 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.Manifest; +import android.app.AppGlobals; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.admin.IDevicePolicyManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.IRestrictionsManager; +import android.content.RestrictionsManager; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.UserInfo; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Binder; +import android.os.Bundle; +import android.os.IUserManager; +import android.os.Process; +import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; + +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 { + 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 { + private 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(String packageName, String requestTemplate, + Bundle requestData) throws RemoteException { + 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_TEMPLATE_ID, requestTemplate); + intent.putExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, requestData); + mContext.sendBroadcastAsUser(intent, 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 + } + } + + @Override + public void notifyPermissionResponse(String packageName, Bundle 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); + } + } + } + } +} |