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