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