Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright 2015 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.camera;
     17 
     18 import android.content.BroadcastReceiver;
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.IntentFilter;
     22 import android.hardware.ICameraService;
     23 import android.hardware.ICameraServiceProxy;
     24 import android.nfc.INfcAdapter;
     25 import android.os.Binder;
     26 import android.os.Handler;
     27 import android.os.IBinder;
     28 import android.os.Message;
     29 import android.os.Process;
     30 import android.os.RemoteException;
     31 import android.os.SystemProperties;
     32 import android.os.UserManager;
     33 import android.util.ArraySet;
     34 import android.util.Slog;
     35 
     36 import com.android.server.ServiceThread;
     37 import com.android.server.SystemService;
     38 
     39 import java.util.Collection;
     40 import java.util.Set;
     41 
     42 /**
     43  * CameraService is the system_server analog to the camera service running in mediaserver.
     44  *
     45  * @hide
     46  */
     47 public class CameraService extends SystemService
     48         implements Handler.Callback, IBinder.DeathRecipient {
     49     private static final String TAG = "CameraService_proxy";
     50     private static final boolean DEBUG = false;
     51 
     52     /**
     53      * This must match the ICameraService.aidl definition
     54      */
     55     private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
     56 
     57     public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy";
     58 
     59     // State arguments to use with the notifyCameraState call from camera service:
     60     public static final int CAMERA_STATE_OPEN = 0;
     61     public static final int CAMERA_STATE_ACTIVE = 1;
     62     public static final int CAMERA_STATE_IDLE = 2;
     63     public static final int CAMERA_STATE_CLOSED = 3;
     64 
     65     // Flags arguments to NFC adapter to enable/disable NFC
     66     public static final int DISABLE_POLLING_FLAGS = 0x1000;
     67     public static final int ENABLE_POLLING_FLAGS = 0x0000;
     68 
     69     // Handler message codes
     70     private static final int MSG_SWITCH_USER = 1;
     71 
     72     private static final int RETRY_DELAY_TIME = 20; //ms
     73 
     74     private final Context mContext;
     75     private final ServiceThread mHandlerThread;
     76     private final Handler mHandler;
     77     private UserManager mUserManager;
     78 
     79     private final Object mLock = new Object();
     80     private Set<Integer> mEnabledCameraUsers;
     81     private int mLastUser;
     82 
     83     private ICameraService mCameraServiceRaw;
     84 
     85     private final ArraySet<String> mActiveCameraIds = new ArraySet<>();
     86 
     87     private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
     88     private static final String NFC_SERVICE_BINDER_NAME = "nfc";
     89     private static final IBinder nfcInterfaceToken = new Binder();
     90 
     91     private final boolean mNotifyNfc;
     92     private int mActiveCameraCount = 0;
     93 
     94     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
     95         @Override
     96         public void onReceive(Context context, Intent intent) {
     97             final String action = intent.getAction();
     98             if (action == null) return;
     99 
    100             switch (action) {
    101                 case Intent.ACTION_USER_ADDED:
    102                 case Intent.ACTION_USER_REMOVED:
    103                 case Intent.ACTION_USER_INFO_CHANGED:
    104                 case Intent.ACTION_MANAGED_PROFILE_ADDED:
    105                 case Intent.ACTION_MANAGED_PROFILE_REMOVED:
    106                     synchronized(mLock) {
    107                         // Return immediately if we haven't seen any users start yet
    108                         if (mEnabledCameraUsers == null) return;
    109                         switchUserLocked(mLastUser);
    110                     }
    111                     break;
    112                 default:
    113                     break; // do nothing
    114             }
    115 
    116         }
    117     };
    118 
    119     private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() {
    120         @Override
    121         public void pingForUserUpdate() {
    122             notifySwitchWithRetries(30);
    123         }
    124 
    125         @Override
    126         public void notifyCameraState(String cameraId, int newCameraState) {
    127             String state = cameraStateToString(newCameraState);
    128             if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " state now " + state);
    129 
    130             updateActivityCount(cameraId, newCameraState);
    131         }
    132     };
    133 
    134     public CameraService(Context context) {
    135         super(context);
    136         mContext = context;
    137         mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY, /*allowTo*/false);
    138         mHandlerThread.start();
    139         mHandler = new Handler(mHandlerThread.getLooper(), this);
    140 
    141         mNotifyNfc = SystemProperties.getInt(NFC_NOTIFICATION_PROP, 0) > 0;
    142         if (DEBUG) Slog.v(TAG, "Notify NFC behavior is " + (mNotifyNfc ? "active" : "disabled"));
    143     }
    144 
    145     @Override
    146     public boolean handleMessage(Message msg) {
    147         switch(msg.what) {
    148             case MSG_SWITCH_USER: {
    149                 notifySwitchWithRetries(msg.arg1);
    150             } break;
    151             default: {
    152                 Slog.e(TAG, "CameraService error, invalid message: " + msg.what);
    153             } break;
    154         }
    155         return true;
    156     }
    157 
    158     @Override
    159     public void onStart() {
    160         mUserManager = UserManager.get(mContext);
    161         if (mUserManager == null) {
    162             // Should never see this unless someone messes up the SystemServer service boot order.
    163             throw new IllegalStateException("UserManagerService must start before CameraService!");
    164         }
    165 
    166         IntentFilter filter = new IntentFilter();
    167         filter.addAction(Intent.ACTION_USER_ADDED);
    168         filter.addAction(Intent.ACTION_USER_REMOVED);
    169         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
    170         filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
    171         filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
    172         mContext.registerReceiver(mIntentReceiver, filter);
    173 
    174         publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy);
    175     }
    176 
    177     @Override
    178     public void onStartUser(int userHandle) {
    179         synchronized(mLock) {
    180             if (mEnabledCameraUsers == null) {
    181                 // Initialize mediaserver, or update mediaserver if we are recovering from a crash.
    182                 switchUserLocked(userHandle);
    183             }
    184         }
    185     }
    186 
    187     @Override
    188     public void onSwitchUser(int userHandle) {
    189         synchronized(mLock) {
    190             switchUserLocked(userHandle);
    191         }
    192     }
    193 
    194     /**
    195      * Handle the death of the native camera service
    196      */
    197     @Override
    198     public void binderDied() {
    199         if (DEBUG) Slog.w(TAG, "Native camera service has died");
    200         synchronized(mLock) {
    201             mCameraServiceRaw = null;
    202 
    203             // All cameras reset to idle on camera service death
    204             boolean wasEmpty = mActiveCameraIds.isEmpty();
    205             mActiveCameraIds.clear();
    206 
    207             if ( mNotifyNfc && !wasEmpty ) {
    208                 notifyNfcService(/*enablePolling*/ true);
    209             }
    210         }
    211     }
    212 
    213     private void switchUserLocked(int userHandle) {
    214         Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle);
    215         mLastUser = userHandle;
    216         if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
    217             // Some user handles have been added or removed, update mediaserver.
    218             mEnabledCameraUsers = currentUserHandles;
    219             notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, currentUserHandles);
    220         }
    221     }
    222 
    223     private Set<Integer> getEnabledUserHandles(int currentUserHandle) {
    224         int[] userProfiles = mUserManager.getEnabledProfileIds(currentUserHandle);
    225         Set<Integer> handles = new ArraySet<>(userProfiles.length);
    226 
    227         for (int id : userProfiles) {
    228             handles.add(id);
    229         }
    230 
    231         return handles;
    232     }
    233 
    234     private void notifySwitchWithRetries(int retries) {
    235         synchronized(mLock) {
    236             if (mEnabledCameraUsers == null) {
    237                 return;
    238             }
    239             if (notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) {
    240                 retries = 0;
    241             }
    242         }
    243         if (retries <= 0) {
    244             return;
    245         }
    246         Slog.i(TAG, "Could not notify camera service of user switch, retrying...");
    247         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWITCH_USER, retries - 1, 0, null),
    248                 RETRY_DELAY_TIME);
    249     }
    250 
    251     private boolean notifyMediaserverLocked(int eventType, Set<Integer> updatedUserHandles) {
    252         // Forward the user switch event to the native camera service running in the mediaserver
    253         // process.
    254         if (mCameraServiceRaw == null) {
    255             IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
    256             if (cameraServiceBinder == null) {
    257                 Slog.w(TAG, "Could not notify mediaserver, camera service not available.");
    258                 return false; // Camera service not active, cannot evict user clients.
    259             }
    260             try {
    261                 cameraServiceBinder.linkToDeath(this, /*flags*/ 0);
    262             } catch (RemoteException e) {
    263                 Slog.w(TAG, "Could not link to death of native camera service");
    264                 return false;
    265             }
    266 
    267             mCameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
    268         }
    269 
    270         try {
    271             mCameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles));
    272         } catch (RemoteException e) {
    273             Slog.w(TAG, "Could not notify mediaserver, remote exception: " + e);
    274             // Not much we can do if camera service is dead.
    275             return false;
    276         }
    277         return true;
    278     }
    279 
    280     private void updateActivityCount(String cameraId, int newCameraState) {
    281         synchronized(mLock) {
    282             boolean wasEmpty = mActiveCameraIds.isEmpty();
    283             switch (newCameraState) {
    284                 case CAMERA_STATE_OPEN:
    285                     break;
    286                 case CAMERA_STATE_ACTIVE:
    287                     mActiveCameraIds.add(cameraId);
    288                     break;
    289                 case CAMERA_STATE_IDLE:
    290                 case CAMERA_STATE_CLOSED:
    291                     mActiveCameraIds.remove(cameraId);
    292                     break;
    293             }
    294             boolean isEmpty = mActiveCameraIds.isEmpty();
    295             if ( mNotifyNfc && (wasEmpty != isEmpty) ) {
    296                 notifyNfcService(isEmpty);
    297             }
    298         }
    299     }
    300 
    301     private void notifyNfcService(boolean enablePolling) {
    302 
    303         IBinder nfcServiceBinder = getBinderService(NFC_SERVICE_BINDER_NAME);
    304         if (nfcServiceBinder == null) {
    305             Slog.w(TAG, "Could not connect to NFC service to notify it of camera state");
    306             return;
    307         }
    308         INfcAdapter nfcAdapterRaw = INfcAdapter.Stub.asInterface(nfcServiceBinder);
    309         int flags = enablePolling ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS;
    310         if (DEBUG) Slog.v(TAG, "Setting NFC reader mode to flags " + flags);
    311         try {
    312             nfcAdapterRaw.setReaderMode(nfcInterfaceToken, null, flags, null);
    313         } catch (RemoteException e) {
    314             Slog.w(TAG, "Could not notify NFC service, remote exception: " + e);
    315         }
    316     }
    317 
    318     private static int[] toArray(Collection<Integer> c) {
    319         int len = c.size();
    320         int[] ret = new int[len];
    321         int idx = 0;
    322         for (Integer i : c) {
    323             ret[idx++] = i;
    324         }
    325         return ret;
    326     }
    327 
    328     private static String cameraStateToString(int newCameraState) {
    329         switch (newCameraState) {
    330             case CAMERA_STATE_OPEN: return "CAMERA_STATE_OPEN";
    331             case CAMERA_STATE_ACTIVE: return "CAMERA_STATE_ACTIVE";
    332             case CAMERA_STATE_IDLE: return "CAMERA_STATE_IDLE";
    333             case CAMERA_STATE_CLOSED: return "CAMERA_STATE_CLOSED";
    334             default: break;
    335         }
    336         return "CAMERA_STATE_UNKNOWN";
    337     }
    338 }
    339