Merge "Persistent connection to DO/PO service." into oc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
dcc792a13f
@ -102,6 +102,7 @@ LOCAL_SRC_FILES += \
|
|||||||
core/java/android/app/IUserSwitchObserver.aidl \
|
core/java/android/app/IUserSwitchObserver.aidl \
|
||||||
core/java/android/app/IWallpaperManager.aidl \
|
core/java/android/app/IWallpaperManager.aidl \
|
||||||
core/java/android/app/IWallpaperManagerCallback.aidl \
|
core/java/android/app/IWallpaperManagerCallback.aidl \
|
||||||
|
core/java/android/app/admin/IDeviceAdminService.aidl \
|
||||||
core/java/android/app/admin/IDevicePolicyManager.aidl \
|
core/java/android/app/admin/IDevicePolicyManager.aidl \
|
||||||
core/java/android/app/trust/IStrongAuthTracker.aidl \
|
core/java/android/app/trust/IStrongAuthTracker.aidl \
|
||||||
core/java/android/app/trust/ITrustManager.aidl \
|
core/java/android/app/trust/ITrustManager.aidl \
|
||||||
|
@ -6232,6 +6232,11 @@ package android.app.admin {
|
|||||||
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
|
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DeviceAdminService extends android.app.Service {
|
||||||
|
ctor public DeviceAdminService();
|
||||||
|
method public final android.os.IBinder onBind(android.content.Intent);
|
||||||
|
}
|
||||||
|
|
||||||
public class DevicePolicyManager {
|
public class DevicePolicyManager {
|
||||||
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
|
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
|
||||||
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
|
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
|
||||||
@ -6398,6 +6403,7 @@ package android.app.admin {
|
|||||||
method public void wipeData(int);
|
method public void wipeData(int);
|
||||||
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
|
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
|
||||||
field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
|
field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
|
||||||
|
field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
|
||||||
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
|
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
|
||||||
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
|
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
|
||||||
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
|
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
|
||||||
|
@ -6435,6 +6435,11 @@ package android.app.admin {
|
|||||||
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
|
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DeviceAdminService extends android.app.Service {
|
||||||
|
ctor public DeviceAdminService();
|
||||||
|
method public final android.os.IBinder onBind(android.content.Intent);
|
||||||
|
}
|
||||||
|
|
||||||
public class DevicePolicyManager {
|
public class DevicePolicyManager {
|
||||||
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
|
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
|
||||||
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
|
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
|
||||||
@ -6622,6 +6627,7 @@ package android.app.admin {
|
|||||||
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
|
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
|
||||||
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
|
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
|
||||||
field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
|
field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
|
||||||
|
field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
|
||||||
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
|
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
|
||||||
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
|
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
|
||||||
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
|
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
|
||||||
|
@ -6251,6 +6251,11 @@ package android.app.admin {
|
|||||||
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
|
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DeviceAdminService extends android.app.Service {
|
||||||
|
ctor public DeviceAdminService();
|
||||||
|
method public final android.os.IBinder onBind(android.content.Intent);
|
||||||
|
}
|
||||||
|
|
||||||
public class DevicePolicyManager {
|
public class DevicePolicyManager {
|
||||||
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
|
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
|
||||||
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
|
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
|
||||||
@ -6426,6 +6431,7 @@ package android.app.admin {
|
|||||||
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
|
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
|
||||||
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
|
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
|
||||||
field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
|
field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
|
||||||
|
field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
|
||||||
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
|
field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
|
||||||
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
|
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
|
||||||
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
|
field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
|
||||||
|
56
core/java/android/app/admin/DeviceAdminService.java
Normal file
56
core/java/android/app/admin/DeviceAdminService.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.app.admin;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for a service that device owner/profile owners can optionally have.
|
||||||
|
*
|
||||||
|
* <p>The system searches for it with an intent filter with the
|
||||||
|
* {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} action, and tries to keep a bound
|
||||||
|
* connection as long as the hosting user is running, so that the device/profile owner is always
|
||||||
|
* considered to be in the foreground.
|
||||||
|
*
|
||||||
|
* <p>Device/profile owners can use
|
||||||
|
* {@link android.content.pm.PackageManager#setComponentEnabledSetting(ComponentName, int, int)}
|
||||||
|
* to disable/enable its own service. For example, when a device/profile owner no longer needs
|
||||||
|
* to be in the foreground, it can (and should) disable its service.
|
||||||
|
*
|
||||||
|
* <p>The service must not be exported.
|
||||||
|
*
|
||||||
|
* <p>TODO: Describe how the system handles crashes in DO/PO.
|
||||||
|
*/
|
||||||
|
public class DeviceAdminService extends Service {
|
||||||
|
private final IDeviceAdminServiceImpl mImpl;
|
||||||
|
|
||||||
|
public DeviceAdminService() {
|
||||||
|
mImpl = new IDeviceAdminServiceImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final IBinder onBind(Intent intent) {
|
||||||
|
return mImpl.asBinder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IDeviceAdminServiceImpl extends IDeviceAdminService.Stub {
|
||||||
|
}
|
||||||
|
|
||||||
|
// So far, we have no methods in this class.
|
||||||
|
}
|
@ -1514,6 +1514,16 @@ public class DevicePolicyManager {
|
|||||||
CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED})
|
CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED})
|
||||||
public @interface ProvisioningPreCondition {}
|
public @interface ProvisioningPreCondition {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service action: Action for a service that device owner and profile owner can optionally
|
||||||
|
* own. If a device owner or a profile owner has such a service, the system tries to keep
|
||||||
|
* a bound connection to it, in order to keep their process always running.
|
||||||
|
* The service must not be exported.
|
||||||
|
*/
|
||||||
|
@SdkConstant(SdkConstantType.SERVICE_ACTION)
|
||||||
|
public static final String ACTION_DEVICE_ADMIN_SERVICE
|
||||||
|
= "android.app.action.DEVICE_ADMIN_SERVICE";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the given administrator component is currently active (enabled) in the system.
|
* Return true if the given administrator component is currently active (enabled) in the system.
|
||||||
*
|
*
|
||||||
|
23
core/java/android/app/admin/IDeviceAdminService.aidl
Normal file
23
core/java/android/app/admin/IDeviceAdminService.aidl
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 android.app.admin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
interface IDeviceAdminService {
|
||||||
|
}
|
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.am;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to a given service component on a given user.
|
||||||
|
*
|
||||||
|
* - Call {@link #connect()} to create a connection.
|
||||||
|
* - Call {@link #disconnect()} to disconnect. Make sure to disconnect when the user stops.
|
||||||
|
*
|
||||||
|
* Add onConnected/onDisconnected callbacks as needed.
|
||||||
|
*/
|
||||||
|
public abstract class PersistentConnection<T> {
|
||||||
|
private final Object mLock = new Object();
|
||||||
|
|
||||||
|
private final String mTag;
|
||||||
|
private final Context mContext;
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final int mUserId;
|
||||||
|
private final ComponentName mComponentName;
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private boolean mStarted;
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private boolean mIsConnected;
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private T mService;
|
||||||
|
|
||||||
|
private final ServiceConnection mServiceConnection = new ServiceConnection() {
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
Slog.i(mTag, "Connected: " + mComponentName.flattenToShortString()
|
||||||
|
+ " u" + mUserId);
|
||||||
|
|
||||||
|
mIsConnected = true;
|
||||||
|
mService = asInterface(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
Slog.i(mTag, "Disconnected: " + mComponentName.flattenToShortString()
|
||||||
|
+ " u" + mUserId);
|
||||||
|
|
||||||
|
cleanUpConnectionLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public PersistentConnection(@NonNull String tag, @NonNull Context context,
|
||||||
|
@NonNull Handler handler, int userId, @NonNull ComponentName componentName) {
|
||||||
|
mTag = tag;
|
||||||
|
mContext = context;
|
||||||
|
mHandler = handler;
|
||||||
|
mUserId = userId;
|
||||||
|
mComponentName = componentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ComponentName getComponentName() {
|
||||||
|
return mComponentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether connected.
|
||||||
|
*/
|
||||||
|
public final boolean isConnected() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
return mIsConnected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the service binder interface.
|
||||||
|
*/
|
||||||
|
public final T getServiceBinder() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
return mService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to the service.
|
||||||
|
*/
|
||||||
|
public final void connect() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mStarted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mStarted = true;
|
||||||
|
|
||||||
|
final Intent service = new Intent().setComponent(mComponentName);
|
||||||
|
|
||||||
|
final boolean success = mContext.bindServiceAsUser(service, mServiceConnection,
|
||||||
|
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
|
||||||
|
mHandler, UserHandle.of(mUserId));
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
Slog.e(mTag, "Binding: " + service.getComponent() + " u" + mUserId
|
||||||
|
+ " failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanUpConnectionLocked() {
|
||||||
|
mIsConnected = false;
|
||||||
|
mService = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect from the service.
|
||||||
|
*/
|
||||||
|
public final void disconnect() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (!mStarted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Slog.i(mTag, "Stopping: " + mComponentName.flattenToShortString() + " u" + mUserId);
|
||||||
|
mStarted = false;
|
||||||
|
mContext.unbindService(mServiceConnection);
|
||||||
|
|
||||||
|
cleanUpConnectionLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Must be implemented by a subclass to convert an {@link IBinder} to a stub. */
|
||||||
|
protected abstract T asInterface(IBinder binder);
|
||||||
|
|
||||||
|
public void dump(String prefix, PrintWriter pw) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
pw.print(prefix);
|
||||||
|
pw.print(mComponentName.flattenToShortString());
|
||||||
|
pw.print(mStarted ? " [started]" : " [not started]");
|
||||||
|
pw.print(mIsConnected ? " [connected]" : " [not connected]");
|
||||||
|
pw.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.devicepolicy;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.app.admin.IDeviceAdminService;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ParceledListSlice;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.content.pm.ServiceInfo;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Slog;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.os.BackgroundThread;
|
||||||
|
import com.android.server.am.PersistentConnection;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages connections to persistent services in owner packages.
|
||||||
|
*/
|
||||||
|
public class DeviceAdminServiceController {
|
||||||
|
static final String TAG = DevicePolicyManagerService.LOG_TAG;
|
||||||
|
|
||||||
|
static final boolean DEBUG = false; // DO NOT MERGE WITH TRUE.
|
||||||
|
|
||||||
|
final Object mLock = new Object();
|
||||||
|
final Context mContext;
|
||||||
|
|
||||||
|
private final DevicePolicyManagerService mService;
|
||||||
|
private final DevicePolicyManagerService.Injector mInjector;
|
||||||
|
|
||||||
|
private final Handler mHandler; // needed?
|
||||||
|
|
||||||
|
static void debug(String format, Object... args) {
|
||||||
|
if (!DEBUG) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Slog.d(TAG, String.format(format, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DevicePolicyServiceConnection
|
||||||
|
extends PersistentConnection<IDeviceAdminService> {
|
||||||
|
public DevicePolicyServiceConnection(int userId, @NonNull ComponentName componentName) {
|
||||||
|
super(TAG, mContext, mHandler, userId, componentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IDeviceAdminService asInterface(IBinder binder) {
|
||||||
|
return IDeviceAdminService.Stub.asInterface(binder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User-ID -> {@link PersistentConnection}.
|
||||||
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private final SparseArray<DevicePolicyServiceConnection> mConnections = new SparseArray<>();
|
||||||
|
|
||||||
|
public DeviceAdminServiceController(DevicePolicyManagerService service) {
|
||||||
|
mService = service;
|
||||||
|
mInjector = service.mInjector;
|
||||||
|
mContext = mInjector.mContext;
|
||||||
|
mHandler = new Handler(BackgroundThread.get().getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a service that handles {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE}
|
||||||
|
* in a given package.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private ServiceInfo findService(@NonNull String packageName, int userId) {
|
||||||
|
final Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE);
|
||||||
|
intent.setPackage(packageName);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final ParceledListSlice<ResolveInfo> pls = mInjector.getIPackageManager()
|
||||||
|
.queryIntentServices(intent, null, /* flags=*/ 0, userId);
|
||||||
|
if (pls == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final List<ResolveInfo> list = pls.getList();
|
||||||
|
if (list.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Note if multiple services are found, that's an error, even if only one of them
|
||||||
|
// is exported.
|
||||||
|
if (list.size() > 1) {
|
||||||
|
Log.e(TAG, "More than one DeviceAdminService's found in package "
|
||||||
|
+ packageName
|
||||||
|
+ ". They'll all be ignored.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final ServiceInfo si = list.get(0).serviceInfo;
|
||||||
|
if (si.exported) {
|
||||||
|
Log.e(TAG, "DeviceAdminService must not be exported: '"
|
||||||
|
+ si.getComponentName().flattenToShortString()
|
||||||
|
+ "' will be ignored.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return si;
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a service that handles {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE}
|
||||||
|
* in an owner package and connect to it.
|
||||||
|
*/
|
||||||
|
public void startServiceForOwner(@NonNull String packageName, int userId,
|
||||||
|
@NonNull String actionForLog) {
|
||||||
|
final long token = mInjector.binderClearCallingIdentity();
|
||||||
|
try {
|
||||||
|
synchronized (mLock) {
|
||||||
|
final ServiceInfo service = findService(packageName, userId);
|
||||||
|
if (service == null) {
|
||||||
|
debug("Owner package %s on u%d has no service.",
|
||||||
|
packageName, userId);
|
||||||
|
disconnectServiceOnUserLocked(userId, actionForLog);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// See if it's already running.
|
||||||
|
final PersistentConnection<IDeviceAdminService> existing =
|
||||||
|
mConnections.get(userId);
|
||||||
|
if (existing != null) {
|
||||||
|
if (existing.getComponentName().equals(service.getComponentName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
disconnectServiceOnUserLocked(userId, actionForLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Owner package %s on u%d has service %s for %s",
|
||||||
|
packageName, userId,
|
||||||
|
service.getComponentName().flattenToShortString(), actionForLog);
|
||||||
|
|
||||||
|
final DevicePolicyServiceConnection conn =
|
||||||
|
new DevicePolicyServiceConnection(
|
||||||
|
userId, service.getComponentName());
|
||||||
|
mConnections.put(userId, conn);
|
||||||
|
conn.connect();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
mInjector.binderRestoreCallingIdentity(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop an owner service on a given user.
|
||||||
|
*/
|
||||||
|
public void stopServiceForOwner(int userId, @NonNull String actionForLog) {
|
||||||
|
final long token = mInjector.binderClearCallingIdentity();
|
||||||
|
try {
|
||||||
|
synchronized (mLock) {
|
||||||
|
disconnectServiceOnUserLocked(userId, actionForLog);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
mInjector.binderRestoreCallingIdentity(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disconnectServiceOnUserLocked(int userId, @NonNull String actionForLog) {
|
||||||
|
final DevicePolicyServiceConnection conn = mConnections.get(userId);
|
||||||
|
if (conn != null) {
|
||||||
|
debug("Stopping service for u%d if already running for %s.",
|
||||||
|
userId, actionForLog);
|
||||||
|
conn.disconnect();
|
||||||
|
mConnections.remove(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(String prefix, PrintWriter pw) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mConnections.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pw.println();
|
||||||
|
pw.print(prefix); pw.println("Owner Services:");
|
||||||
|
for (int i = 0; i < mConnections.size(); i++) {
|
||||||
|
final int userId = mConnections.keyAt(i);
|
||||||
|
pw.print(prefix); pw.print(" "); pw.print("User: "); pw.println(userId);
|
||||||
|
|
||||||
|
final DevicePolicyServiceConnection con = mConnections.valueAt(i);
|
||||||
|
con.dump(prefix + " ", pw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -140,7 +140,6 @@ import android.os.storage.StorageManager;
|
|||||||
import android.provider.ContactsContract.QuickContact;
|
import android.provider.ContactsContract.QuickContact;
|
||||||
import android.provider.ContactsInternal;
|
import android.provider.ContactsInternal;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.security.Credentials;
|
|
||||||
import android.security.IKeyChainAliasCallback;
|
import android.security.IKeyChainAliasCallback;
|
||||||
import android.security.IKeyChainService;
|
import android.security.IKeyChainService;
|
||||||
import android.security.KeyChain;
|
import android.security.KeyChain;
|
||||||
@ -194,7 +193,6 @@ import java.io.IOException;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -365,6 +363,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
final UserManagerInternal mUserManagerInternal;
|
final UserManagerInternal mUserManagerInternal;
|
||||||
final TelephonyManager mTelephonyManager;
|
final TelephonyManager mTelephonyManager;
|
||||||
private final LockPatternUtils mLockPatternUtils;
|
private final LockPatternUtils mLockPatternUtils;
|
||||||
|
private final DeviceAdminServiceController mDeviceAdminServiceController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
|
* Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
|
||||||
@ -459,7 +458,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartUser(int userHandle) {
|
public void onStartUser(int userHandle) {
|
||||||
mService.onStartUser(userHandle);
|
mService.handleStartUser(userHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnlockUser(int userHandle) {
|
||||||
|
mService.handleUnlockUser(userHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopUser(int userHandle) {
|
||||||
|
mService.handleStopUser(userHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1420,7 +1429,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handlePackagesChanged(String packageName, int userHandle) {
|
private void handlePackagesChanged(@Nullable String packageName, int userHandle) {
|
||||||
boolean removedAdmin = false;
|
boolean removedAdmin = false;
|
||||||
if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
|
if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
|
||||||
DevicePolicyData policy = getUserData(userHandle);
|
DevicePolicyData policy = getUserData(userHandle);
|
||||||
@ -1461,6 +1470,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it's an owner package, we may need to refresh the bound connection.
|
||||||
|
final ComponentName owner = getOwnerComponent(userHandle);
|
||||||
|
if ((packageName != null) && (owner != null)
|
||||||
|
&& (owner.getPackageName().equals(packageName))) {
|
||||||
|
startOwnerService(userHandle, "package-broadcast");
|
||||||
|
}
|
||||||
|
|
||||||
// Persist updates if the removed package was an admin or delegate.
|
// Persist updates if the removed package was an admin or delegate.
|
||||||
if (removedAdmin || removedDelegate) {
|
if (removedAdmin || removedDelegate) {
|
||||||
saveSettingsLocked(policy.mUserHandle);
|
saveSettingsLocked(policy.mUserHandle);
|
||||||
@ -1791,6 +1807,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
// Needed when mHasFeature == false, because it controls the certificate warning text.
|
// Needed when mHasFeature == false, because it controls the certificate warning text.
|
||||||
mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler);
|
mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler);
|
||||||
|
|
||||||
|
mDeviceAdminServiceController = new DeviceAdminServiceController(this);
|
||||||
|
|
||||||
if (!mHasFeature) {
|
if (!mHasFeature) {
|
||||||
// Skip the rest of the initialization
|
// Skip the rest of the initialization
|
||||||
return;
|
return;
|
||||||
@ -2943,7 +2961,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
loadOwners();
|
loadOwners();
|
||||||
cleanUpOldUsers();
|
cleanUpOldUsers();
|
||||||
ensureUnknownSourcesRestrictionForProfileOwners();
|
ensureUnknownSourcesRestrictionForProfileOwners();
|
||||||
onStartUser(UserHandle.USER_SYSTEM);
|
handleStartUser(UserHandle.USER_SYSTEM);
|
||||||
|
|
||||||
// Register an observer for watching for user setup complete and settings changes.
|
// Register an observer for watching for user setup complete and settings changes.
|
||||||
mSetupContentObserver.register();
|
mSetupContentObserver.register();
|
||||||
@ -2990,10 +3008,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onStartUser(int userId) {
|
void handleStartUser(int userId) {
|
||||||
updateScreenCaptureDisabledInWindowManager(userId,
|
updateScreenCaptureDisabledInWindowManager(userId,
|
||||||
getScreenCaptureDisabled(null, userId));
|
getScreenCaptureDisabled(null, userId));
|
||||||
pushUserRestrictions(userId);
|
pushUserRestrictions(userId);
|
||||||
|
|
||||||
|
startOwnerService(userId, "start-user");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleUnlockUser(int userId) {
|
||||||
|
startOwnerService(userId, "unlock-user");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleStopUser(int userId) {
|
||||||
|
stopOwnerService(userId, "stop-user");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startOwnerService(int userId, String actionForLog) {
|
||||||
|
final ComponentName owner = getOwnerComponent(userId);
|
||||||
|
if (owner != null) {
|
||||||
|
mDeviceAdminServiceController.startServiceForOwner(
|
||||||
|
owner.getPackageName(), userId, actionForLog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopOwnerService(int userId, String actionForLog) {
|
||||||
|
mDeviceAdminServiceController.stopServiceForOwner(userId, actionForLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanUpOldUsers() {
|
private void cleanUpOldUsers() {
|
||||||
@ -5078,7 +5118,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
* @param callerPackage the name of the calling package. Required if {@code who} is
|
* @param callerPackage the name of the calling package. Required if {@code who} is
|
||||||
* {@code null}.
|
* {@code null}.
|
||||||
* @param reqPolicy the policy used in the API whose access permission is being checked.
|
* @param reqPolicy the policy used in the API whose access permission is being checked.
|
||||||
* @param scoppe the delegation scope corresponding to the API being checked.
|
* @param scope the delegation scope corresponding to the API being checked.
|
||||||
* @throws SecurityException if {@code who} is given and is not an owner for {@code reqPolicy};
|
* @throws SecurityException if {@code who} is given and is not an owner for {@code reqPolicy};
|
||||||
* or when {@code who} is {@code null} and {@code callerPackage} is not a delegate
|
* or when {@code who} is {@code null} and {@code callerPackage} is not a delegate
|
||||||
* of {@code scope}.
|
* of {@code scope}.
|
||||||
@ -6460,6 +6500,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
} finally {
|
} finally {
|
||||||
mInjector.binderRestoreCallingIdentity(ident);
|
mInjector.binderRestoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
|
mDeviceAdminServiceController.startServiceForOwner(
|
||||||
|
admin.getPackageName(), userId, "set-device-owner");
|
||||||
|
|
||||||
Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
|
Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -6615,6 +6658,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) {
|
private void clearDeviceOwnerLocked(ActiveAdmin admin, int userId) {
|
||||||
|
mDeviceAdminServiceController.stopServiceForOwner(userId, "clear-device-owner");
|
||||||
|
|
||||||
if (admin != null) {
|
if (admin != null) {
|
||||||
admin.disableCamera = false;
|
admin.disableCamera = false;
|
||||||
admin.userRestrictions = null;
|
admin.userRestrictions = null;
|
||||||
@ -6692,6 +6737,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
} finally {
|
} finally {
|
||||||
mInjector.binderRestoreCallingIdentity(id);
|
mInjector.binderRestoreCallingIdentity(id);
|
||||||
}
|
}
|
||||||
|
mDeviceAdminServiceController.startServiceForOwner(
|
||||||
|
who.getPackageName(), userHandle, "set-profile-owner");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6723,6 +6770,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void clearProfileOwnerLocked(ActiveAdmin admin, int userId) {
|
public void clearProfileOwnerLocked(ActiveAdmin admin, int userId) {
|
||||||
|
mDeviceAdminServiceController.stopServiceForOwner(userId, "clear-profile-owner");
|
||||||
|
|
||||||
if (admin != null) {
|
if (admin != null) {
|
||||||
admin.disableCamera = false;
|
admin.disableCamera = false;
|
||||||
admin.userRestrictions = null;
|
admin.userRestrictions = null;
|
||||||
@ -7275,6 +7324,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
pw.println("Current Device Policy Manager state:");
|
pw.println("Current Device Policy Manager state:");
|
||||||
mOwners.dump(" ", pw);
|
mOwners.dump(" ", pw);
|
||||||
|
mDeviceAdminServiceController.dump(" ", pw);
|
||||||
int userCount = mUserData.size();
|
int userCount = mUserData.size();
|
||||||
for (int u = 0; u < userCount; u++) {
|
for (int u = 0; u < userCount; u++) {
|
||||||
DevicePolicyData policy = getUserData(mUserData.keyAt(u));
|
DevicePolicyData policy = getUserData(mUserData.keyAt(u));
|
||||||
@ -9624,6 +9674,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return device owner or profile owner set on a given user.
|
||||||
|
*/
|
||||||
|
private @Nullable ComponentName getOwnerComponent(int userId) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (mOwners.getDeviceOwnerUserId() == userId) {
|
||||||
|
return mOwners.getDeviceOwnerComponent();
|
||||||
|
}
|
||||||
|
if (mOwners.hasProfileOwner(userId)) {
|
||||||
|
return mOwners.getProfileOwnerComponent(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private int checkManagedUserProvisioningPreCondition(int callingUserId) {
|
private int checkManagedUserProvisioningPreCondition(int callingUserId) {
|
||||||
if (!hasFeatureManagedUsers()) {
|
if (!hasFeatureManagedUsers()) {
|
||||||
return CODE_MANAGED_USERS_NOT_SUPPORTED;
|
return CODE_MANAGED_USERS_NOT_SUPPORTED;
|
||||||
|
Reference in New Issue
Block a user