1 /* 2 * Copyright (C) 2017 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 package com.android.server.devicepolicy; 17 18 import android.Manifest.permission; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.admin.DeviceAdminService; 22 import android.app.admin.DevicePolicyManager; 23 import android.app.admin.IDeviceAdminService; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.pm.ServiceInfo; 27 import android.os.Handler; 28 import android.os.IBinder; 29 import android.util.IndentingPrintWriter; 30 import android.util.SparseArray; 31 32 import com.android.internal.annotations.GuardedBy; 33 import com.android.internal.os.BackgroundThread; 34 import com.android.server.am.PersistentConnection; 35 import com.android.server.appbinding.AppBindingUtils; 36 import com.android.server.utils.Slogf; 37 38 /** 39 * Manages connections to persistent services in owner packages. 40 */ 41 public class DeviceAdminServiceController { 42 static final String TAG = DevicePolicyManagerService.LOG_TAG; 43 44 static final boolean DEBUG = false; // DO NOT MERGE WITH TRUE. 45 46 final Object mLock = new Object(); 47 final Context mContext; 48 49 private final DevicePolicyManagerService.Injector mInjector; 50 private final DevicePolicyConstants mConstants; 51 52 private final Handler mHandler; // needed? 53 54 private class DevicePolicyServiceConnection 55 extends PersistentConnection<IDeviceAdminService> { DevicePolicyServiceConnection(int userId, @NonNull ComponentName componentName)56 public DevicePolicyServiceConnection(int userId, @NonNull ComponentName componentName) { 57 super(TAG, mContext, mHandler, userId, componentName, 58 mConstants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_SEC, 59 mConstants.DAS_DIED_SERVICE_RECONNECT_BACKOFF_INCREASE, 60 mConstants.DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC, 61 mConstants.DAS_DIED_SERVICE_STABLE_CONNECTION_THRESHOLD_SEC); 62 } 63 64 @Override getBindFlags()65 protected int getBindFlags() { 66 return Context.BIND_FOREGROUND_SERVICE; 67 } 68 69 @Override asInterface(IBinder binder)70 protected IDeviceAdminService asInterface(IBinder binder) { 71 return IDeviceAdminService.Stub.asInterface(binder); 72 } 73 } 74 75 /** 76 * User-ID -> {@link PersistentConnection}. 77 */ 78 @GuardedBy("mLock") 79 private final SparseArray<DevicePolicyServiceConnection> mConnections = new SparseArray<>(); 80 DeviceAdminServiceController(DevicePolicyManagerService service, DevicePolicyConstants constants)81 public DeviceAdminServiceController(DevicePolicyManagerService service, 82 DevicePolicyConstants constants) { 83 mInjector = service.mInjector; 84 mContext = mInjector.mContext; 85 mHandler = new Handler(BackgroundThread.get().getLooper()); 86 mConstants = constants; 87 } 88 89 /** 90 * Find a service that handles {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} 91 * in a given package. 92 */ 93 @Nullable findService(@onNull String packageName, int userId)94 private ServiceInfo findService(@NonNull String packageName, int userId) { 95 return AppBindingUtils.findService( 96 packageName, 97 userId, 98 DevicePolicyManager.ACTION_DEVICE_ADMIN_SERVICE, 99 permission.BIND_DEVICE_ADMIN, 100 DeviceAdminService.class, 101 mInjector.getIPackageManager(), 102 new StringBuilder() /* ignore error message */); 103 } 104 105 /** 106 * Find a service that handles {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} 107 * in an owner package and connect to it. 108 */ startServiceForOwner(@onNull String packageName, int userId, @NonNull String actionForLog)109 public void startServiceForOwner(@NonNull String packageName, int userId, 110 @NonNull String actionForLog) { 111 final long token = mInjector.binderClearCallingIdentity(); 112 try { 113 synchronized (mLock) { 114 final ServiceInfo service = findService(packageName, userId); 115 if (service == null) { 116 if (DEBUG) { 117 Slogf.d(TAG, "Owner package %s on u%d has no service.", packageName, 118 userId); 119 } 120 disconnectServiceOnUserLocked(userId, actionForLog); 121 return; 122 } 123 // See if it's already running. 124 final PersistentConnection<IDeviceAdminService> existing = 125 mConnections.get(userId); 126 if (existing != null) { 127 // Note even when we're already connected to the same service, the binding 128 // would have died at this point due to a package update. So we disconnect 129 // anyway and re-connect. 130 if (DEBUG) { 131 Slogf.d("Disconnecting from existing service connection.", packageName, 132 userId); 133 } 134 disconnectServiceOnUserLocked(userId, actionForLog); 135 } 136 137 if (DEBUG) { 138 Slogf.d("Owner package %s on u%d has service %s for %s", packageName, userId, 139 service.getComponentName().flattenToShortString(), actionForLog); 140 } 141 142 final DevicePolicyServiceConnection conn = 143 new DevicePolicyServiceConnection( 144 userId, service.getComponentName()); 145 mConnections.put(userId, conn); 146 conn.bind(); 147 } 148 } finally { 149 mInjector.binderRestoreCallingIdentity(token); 150 } 151 } 152 153 /** 154 * Stop an owner service on a given user. 155 */ stopServiceForOwner(int userId, @NonNull String actionForLog)156 public void stopServiceForOwner(int userId, @NonNull String actionForLog) { 157 final long token = mInjector.binderClearCallingIdentity(); 158 try { 159 synchronized (mLock) { 160 disconnectServiceOnUserLocked(userId, actionForLog); 161 } 162 } finally { 163 mInjector.binderRestoreCallingIdentity(token); 164 } 165 } 166 167 @GuardedBy("mLock") disconnectServiceOnUserLocked(int userId, @NonNull String actionForLog)168 private void disconnectServiceOnUserLocked(int userId, @NonNull String actionForLog) { 169 final DevicePolicyServiceConnection conn = mConnections.get(userId); 170 if (conn != null) { 171 if (DEBUG) { 172 Slogf.d(TAG, "Stopping service for u%d if already running for %s.", userId, 173 actionForLog); 174 } 175 conn.unbind(); 176 mConnections.remove(userId); 177 } 178 } 179 180 /** dump content */ dump(IndentingPrintWriter pw)181 public void dump(IndentingPrintWriter pw) { 182 synchronized (mLock) { 183 if (mConnections.size() == 0) { 184 return; 185 } 186 pw.println("Owner Services:"); 187 pw.increaseIndent(); 188 for (int i = 0; i < mConnections.size(); i++) { 189 final int userId = mConnections.keyAt(i); 190 pw.print("User: "); pw.println(userId); 191 192 final DevicePolicyServiceConnection con = mConnections.valueAt(i); 193 pw.increaseIndent(); 194 con.dump("", pw); 195 pw.decreaseIndent(); 196 } 197 pw.decreaseIndent(); 198 } 199 } 200 } 201