method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+ method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+ method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
+ method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
return bindServiceCommon(service, conn, flags, handler, user);
}
+ /** @hide */
+ @Override
+ public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+ int flags) {
+ return mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
+ }
+
+ /** @hide */
+ @Override
+ public IApplicationThread getIApplicationThread() {
+ return mMainThread.getApplicationThread();
+ }
+
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
+ // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
return mOuterContext;
}
- final IBinder getActivityToken() {
+ @Override
+ public IBinder getActivityToken() {
return mActivityToken;
}
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.Activity;
-import android.app.admin.NetworkEvent;
import android.app.admin.PasswordMetrics;
+import android.app.IServiceConnection;
import android.app.admin.SecurityLog.SecurityEvent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.ServiceManager.ServiceNotFoundException;
import android.provider.ContactsContract.Directory;
import android.provider.Settings;
import android.security.Credentials;
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Called by device owner/ profile owner in managed profile to bind the service with each other.
+ * The service must be unexported. Note that the {@link Context} used to obtain this
+ * {@link DevicePolicyManager} instance via {@link Context#getSystemService(Class)} will be used
+ * to bind to the {@link android.app.Service}.
+ * STOPSHIP (b/31952368): Update the javadoc after we policy to control which packages can talk.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param serviceIntent Identifies the service to connect to. The Intent must specify either an
+ * explicit component name or a package name to match an
+ * {@link IntentFilter} published by a service.
+ * @param conn Receives information as the service is started and stopped. This must be a
+ * valid {@link ServiceConnection} object; it must not be {@code null}.
+ * @param flags Operation options for the binding operation. See
+ * {@link Context#bindService(Intent, ServiceConnection, int)}.
+ * @param targetUser Which user to bind to.
+ * @return If you have successfully bound to the service, {@code true} is returned;
+ * {@code false} is returned if the connection is not made and you will not
+ * receive the service object.
+ * @see Context#bindService(Intent, ServiceConnection, int)
+ */
+ public boolean bindDeviceAdminServiceAsUser(
+ @NonNull ComponentName admin, Intent serviceIntent, @NonNull ServiceConnection conn,
+ @Context.BindServiceFlags int flags, @NonNull UserHandle targetUser) {
+ throwIfParentInstance("bindDeviceAdminServiceAsUser");
+ // Keep this in sync with ContextImpl.bindServiceCommon.
+ try {
+ final IServiceConnection sd = mContext.getServiceDispatcher(conn, null, flags);
+ serviceIntent.prepareToLeaveProcess(mContext);
+ return mService.bindDeviceAdminServiceAsUser(admin,
+ mContext.getIApplicationThread(), mContext.getActivityToken(), serviceIntent,
+ sd, flags, targetUser.getIdentifier());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
package android.app.admin;
import android.app.admin.NetworkEvent;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.PasswordMetrics;
import android.content.ComponentName;
void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled);
boolean isNetworkLoggingEnabled(in ComponentName admin);
List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin, long batchToken);
+
+ boolean bindDeviceAdminServiceAsUser(in ComponentName admin,
+ IApplicationThread caller, IBinder token, in Intent service,
+ IServiceConnection connection, int flags, int targetUserId);
}
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
+import android.app.LoadedApk;
+import android.app.admin.DevicePolicyManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
public boolean isCredentialEncryptedStorage() {
return isCredentialProtectedStorage();
}
+
+ /**
+ * @hide
+ */
+ public IBinder getActivityToken() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+ int flags) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
+ * @hide
+ */
+ public IApplicationThread getIApplicationThread() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
}
package android.content;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
public boolean isCredentialProtectedStorage() {
return mBase.isCredentialProtectedStorage();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public IBinder getActivityToken() {
+ return mBase.getActivityToken();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+ int flags) {
+ return mBase.getServiceDispatcher(conn, handler, flags);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public IApplicationThread getIApplicationThread() {
+ return mBase.getIApplicationThread();
+ }
}
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.ParcelableString;
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
}
+ PackageManager getPackageManager() {
+ return mContext.getPackageManager();
+ }
+
PowerManagerInternal getPowerManagerInternal() {
return LocalServices.getService(PowerManagerInternal.class);
}
}
}
+ boolean isDeviceOwner(ActiveAdmin admin) {
+ return isDeviceOwner(admin.info.getComponent(), admin.getUserHandle().getIdentifier());
+ }
+
public boolean isDeviceOwner(ComponentName who, int userId) {
synchronized (this) {
return mOwners.hasDeviceOwner()
}
}
+ @Override
+ public boolean bindDeviceAdminServiceAsUser(
+ @NonNull ComponentName admin, @NonNull IApplicationThread caller,
+ @Nullable IBinder activtiyToken, @NonNull Intent serviceIntent,
+ @NonNull IServiceConnection connection, int flags, @UserIdInt int targetUserId) {
+ if (!mHasFeature) {
+ return false;
+ }
+ Preconditions.checkNotNull(admin);
+ Preconditions.checkNotNull(caller);
+ Preconditions.checkNotNull(serviceIntent);
+ Preconditions.checkNotNull(connection);
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
+ Preconditions.checkArgument(callingUserId != targetUserId,
+ "target user id must be different from the calling user id");
+
+ synchronized (this) {
+ final ActiveAdmin callingAdmin = getActiveAdminForCallerLocked(admin,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ // Ensure the target user is valid.
+ if (isDeviceOwner(callingAdmin)) {
+ enforceManagedProfile(targetUserId, "Target user must be a managed profile");
+ } else {
+ // Further lock down to profile owner in managed profile.
+ enforceManagedProfile(callingUserId,
+ "Only support profile owner in managed profile.");
+ if (mOwners.getDeviceOwnerUserId() != targetUserId) {
+ throw new SecurityException("Target user must be a device owner.");
+ }
+ }
+ }
+ final long callingIdentity = mInjector.binderClearCallingIdentity();
+ try {
+ if (!mUserManager.isSameProfileGroup(callingUserId, targetUserId)) {
+ throw new SecurityException(
+ "Can only bind service across users under the same profile group");
+ }
+ final String targetPackage;
+ synchronized (this) {
+ targetPackage = getOwnerPackageNameForUserLocked(targetUserId);
+ }
+ // STOPSHIP(b/31952368): Add policy to control which packages can talk.
+ if (TextUtils.isEmpty(targetPackage) || !targetPackage.equals(admin.getPackageName())) {
+ throw new SecurityException("Device owner and profile owner must be the same " +
+ "package in order to communicate.");
+ }
+ // Validate and sanitize the incoming service intent.
+ final Intent sanitizedIntent =
+ createCrossUserServiceIntent(serviceIntent, targetPackage);
+ if (sanitizedIntent == null) {
+ // Fail, cannot lookup the target service.
+ throw new SecurityException("Invalid intent or failed to look up the service");
+ }
+ // Ask ActivityManager to bind it. Notice that we are binding the service with the
+ // caller app instead of DevicePolicyManagerService.
+ try {
+ return mInjector.getIActivityManager().bindService(
+ caller, activtiyToken, serviceIntent,
+ serviceIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ connection, flags, mContext.getOpPackageName(),
+ targetUserId) != 0;
+ } catch (RemoteException ex) {
+ // Same process, should not happen.
+ }
+ } finally {
+ mInjector.binderRestoreCallingIdentity(callingIdentity);
+ }
+ // Fail to bind.
+ return false;
+ }
+
/**
* Return true if a given user has any accounts that'll prevent installing a device or profile
* owner {@code owner}.
? mNetworkLogger.retrieveLogs(batchToken)
: null;
}
+
+ /**
+ * Return the package name of owner in a given user.
+ */
+ private String getOwnerPackageNameForUserLocked(int userId) {
+ return getDeviceOwnerUserId() == userId
+ ? mOwners.getDeviceOwnerPackageName()
+ : mOwners.getProfileOwnerPackage(userId);
+ }
+
+ /**
+ * @param rawIntent Original service intent specified by caller.
+ * @param expectedPackageName The expected package name in the incoming intent.
+ * @return Intent that have component explicitly set. {@code null} if the incoming intent
+ * or target service is invalid.
+ */
+ private Intent createCrossUserServiceIntent (
+ @NonNull Intent rawIntent, @NonNull String expectedPackageName) {
+ if (rawIntent.getComponent() == null && rawIntent.getPackage() == null) {
+ Log.e(LOG_TAG, "Service intent must be explicit (with a package name or component): "
+ + rawIntent);
+ return null;
+ }
+ ResolveInfo info = mInjector.getPackageManager().resolveService(rawIntent, 0);
+ if (info == null || info.serviceInfo == null) {
+ Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent);
+ return null;
+ }
+ if (!expectedPackageName.equals(info.serviceInfo.packageName)) {
+ Log.e(LOG_TAG, "Only allow to bind service in " + expectedPackageName);
+ return null;
+ }
+ if (info.serviceInfo.exported) {
+ Log.e(LOG_TAG, "The service must be unexported.");
+ return null;
+ }
+ // It is the system server to bind the service, it would be extremely dangerous if it
+ // can be exploited to bind any service. Set the component explicitly to make sure we
+ // do not bind anything accidentally.
+ rawIntent.setComponent(info.serviceInfo.getComponentName());
+ return rawIntent;
+ }
}
package android.test.mock;
import android.annotation.SystemApi;
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
public boolean isCredentialProtectedStorage() {
throw new UnsupportedOperationException();
}
+
+ /** {@hide} */
+ @Override
+ public IBinder getActivityToken() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@hide} */
+ @Override
+ public IServiceConnection getServiceDispatcher(ServiceConnection conn, Handler handler,
+ int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@hide} */
+ @Override
+ public IApplicationThread getIApplicationThread() {
+ throw new UnsupportedOperationException();
+ }
}