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