Home | History | Annotate | Download | only in devicepolicy
      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 
     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> {
     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
     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 
     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
    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      */
    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      */
    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")
    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 
    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