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.metrics.LogMaker; 25 import android.nfc.INfcAdapter; 26 import android.os.Binder; 27 import android.os.Handler; 28 import android.os.IBinder; 29 import android.os.Message; 30 import android.os.Process; 31 import android.os.RemoteException; 32 import android.os.SystemClock; 33 import android.os.SystemProperties; 34 import android.os.UserManager; 35 import android.util.ArrayMap; 36 import android.util.ArraySet; 37 import android.util.Slog; 38 39 import com.android.internal.logging.MetricsLogger; 40 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 41 import com.android.server.LocalServices; 42 import com.android.server.ServiceThread; 43 import com.android.server.SystemService; 44 45 import java.util.ArrayList; 46 import java.util.Collection; 47 import java.util.Collections; 48 import java.util.List; 49 import java.util.Set; 50 51 /** 52 * CameraServiceProxy is the system_server analog to the camera service running in mediaserver. 53 * 54 * @hide 55 */ 56 public class CameraServiceProxy extends SystemService 57 implements Handler.Callback, IBinder.DeathRecipient { 58 private static final String TAG = "CameraService_proxy"; 59 private static final boolean DEBUG = false; 60 61 /** 62 * This must match the ICameraService.aidl definition 63 */ 64 private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera"; 65 66 public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy"; 67 68 // Flags arguments to NFC adapter to enable/disable NFC 69 public static final int DISABLE_POLLING_FLAGS = 0x1000; 70 public static final int ENABLE_POLLING_FLAGS = 0x0000; 71 72 // Handler message codes 73 private static final int MSG_SWITCH_USER = 1; 74 75 private static final int RETRY_DELAY_TIME = 20; //ms 76 77 // Maximum entries to keep in usage history before dumping out 78 private static final int MAX_USAGE_HISTORY = 100; 79 80 private final Context mContext; 81 private final ServiceThread mHandlerThread; 82 private final Handler mHandler; 83 private UserManager mUserManager; 84 85 private final Object mLock = new Object(); 86 private Set<Integer> mEnabledCameraUsers; 87 private int mLastUser; 88 89 private ICameraService mCameraServiceRaw; 90 91 private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>(); 92 private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>(); 93 private final MetricsLogger mLogger = new MetricsLogger(); 94 private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc"; 95 private static final String NFC_SERVICE_BINDER_NAME = "nfc"; 96 private static final IBinder nfcInterfaceToken = new Binder(); 97 98 private final boolean mNotifyNfc; 99 100 /** 101 * Structure to track camera usage 102 */ 103 private static class CameraUsageEvent { 104 public final int mCameraFacing; 105 public final String mClientName; 106 107 private boolean mCompleted; 108 private long mDurationOrStartTimeMs; // Either start time, or duration once completed 109 110 public CameraUsageEvent(int facing, String clientName) { 111 mCameraFacing = facing; 112 mClientName = clientName; 113 mDurationOrStartTimeMs = SystemClock.elapsedRealtime(); 114 mCompleted = false; 115 } 116 117 public void markCompleted() { 118 if (mCompleted) { 119 return; 120 } 121 mCompleted = true; 122 mDurationOrStartTimeMs = SystemClock.elapsedRealtime() - mDurationOrStartTimeMs; 123 if (CameraServiceProxy.DEBUG) { 124 Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) + 125 " was in use by " + mClientName + " for " + 126 mDurationOrStartTimeMs + " ms"); 127 } 128 } 129 130 /** 131 * Return duration of camera usage event, or 0 if the event is not done 132 */ 133 public long getDuration() { 134 return mCompleted ? mDurationOrStartTimeMs : 0; 135 } 136 } 137 138 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 139 @Override 140 public void onReceive(Context context, Intent intent) { 141 final String action = intent.getAction(); 142 if (action == null) return; 143 144 switch (action) { 145 case Intent.ACTION_USER_ADDED: 146 case Intent.ACTION_USER_REMOVED: 147 case Intent.ACTION_USER_INFO_CHANGED: 148 case Intent.ACTION_MANAGED_PROFILE_ADDED: 149 case Intent.ACTION_MANAGED_PROFILE_REMOVED: 150 synchronized(mLock) { 151 // Return immediately if we haven't seen any users start yet 152 if (mEnabledCameraUsers == null) return; 153 switchUserLocked(mLastUser); 154 } 155 break; 156 default: 157 break; // do nothing 158 } 159 160 } 161 }; 162 163 private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() { 164 @Override 165 public void pingForUserUpdate() { 166 notifySwitchWithRetries(30); 167 } 168 169 @Override 170 public void notifyCameraState(String cameraId, int newCameraState, int facing, 171 String clientName) { 172 String state = cameraStateToString(newCameraState); 173 String facingStr = cameraFacingToString(facing); 174 if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " + 175 state + " for client " + clientName); 176 177 updateActivityCount(cameraId, newCameraState, facing, clientName); 178 } 179 }; 180 181 public CameraServiceProxy(Context context) { 182 super(context); 183 mContext = context; 184 mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY, /*allowTo*/false); 185 mHandlerThread.start(); 186 mHandler = new Handler(mHandlerThread.getLooper(), this); 187 188 mNotifyNfc = SystemProperties.getInt(NFC_NOTIFICATION_PROP, 0) > 0; 189 if (DEBUG) Slog.v(TAG, "Notify NFC behavior is " + (mNotifyNfc ? "active" : "disabled")); 190 } 191 192 @Override 193 public boolean handleMessage(Message msg) { 194 switch(msg.what) { 195 case MSG_SWITCH_USER: { 196 notifySwitchWithRetries(msg.arg1); 197 } break; 198 default: { 199 Slog.e(TAG, "CameraServiceProxy error, invalid message: " + msg.what); 200 } break; 201 } 202 return true; 203 } 204 205 @Override 206 public void onStart() { 207 mUserManager = UserManager.get(mContext); 208 if (mUserManager == null) { 209 // Should never see this unless someone messes up the SystemServer service boot order. 210 throw new IllegalStateException("UserManagerService must start before" + 211 " CameraServiceProxy!"); 212 } 213 214 IntentFilter filter = new IntentFilter(); 215 filter.addAction(Intent.ACTION_USER_ADDED); 216 filter.addAction(Intent.ACTION_USER_REMOVED); 217 filter.addAction(Intent.ACTION_USER_INFO_CHANGED); 218 filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 219 filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 220 mContext.registerReceiver(mIntentReceiver, filter); 221 222 publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy); 223 publishLocalService(CameraServiceProxy.class, this); 224 225 CameraStatsJobService.schedule(mContext); 226 } 227 228 @Override 229 public void onStartUser(int userHandle) { 230 synchronized(mLock) { 231 if (mEnabledCameraUsers == null) { 232 // Initialize mediaserver, or update mediaserver if we are recovering from a crash. 233 switchUserLocked(userHandle); 234 } 235 } 236 } 237 238 @Override 239 public void onSwitchUser(int userHandle) { 240 synchronized(mLock) { 241 switchUserLocked(userHandle); 242 } 243 } 244 245 /** 246 * Handle the death of the native camera service 247 */ 248 @Override 249 public void binderDied() { 250 if (DEBUG) Slog.w(TAG, "Native camera service has died"); 251 synchronized(mLock) { 252 mCameraServiceRaw = null; 253 254 // All cameras reset to idle on camera service death 255 boolean wasEmpty = mActiveCameraUsage.isEmpty(); 256 mActiveCameraUsage.clear(); 257 258 if ( mNotifyNfc && !wasEmpty ) { 259 notifyNfcService(/*enablePolling*/ true); 260 } 261 } 262 } 263 264 /** 265 * Dump camera usage events to log. 266 * Package-private 267 */ 268 void dumpUsageEvents() { 269 synchronized(mLock) { 270 // Randomize order of events so that it's not meaningful 271 Collections.shuffle(mCameraUsageHistory); 272 for (CameraUsageEvent e : mCameraUsageHistory) { 273 if (DEBUG) { 274 Slog.v(TAG, "Camera: " + e.mClientName + " used a camera facing " + 275 cameraFacingToString(e.mCameraFacing) + " for " + 276 e.getDuration() + " ms"); 277 } 278 int subtype = 0; 279 switch(e.mCameraFacing) { 280 case ICameraServiceProxy.CAMERA_FACING_BACK: 281 subtype = MetricsEvent.CAMERA_BACK_USED; 282 break; 283 case ICameraServiceProxy.CAMERA_FACING_FRONT: 284 subtype = MetricsEvent.CAMERA_FRONT_USED; 285 break; 286 case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: 287 subtype = MetricsEvent.CAMERA_EXTERNAL_USED; 288 break; 289 default: 290 continue; 291 } 292 LogMaker l = new LogMaker(MetricsEvent.ACTION_CAMERA_EVENT) 293 .setType(MetricsEvent.TYPE_ACTION) 294 .setSubtype(subtype) 295 .setLatency(e.getDuration()) 296 .setPackageName(e.mClientName); 297 mLogger.write(l); 298 } 299 mCameraUsageHistory.clear(); 300 } 301 CameraStatsJobService.schedule(mContext); 302 } 303 304 private void switchUserLocked(int userHandle) { 305 Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle); 306 mLastUser = userHandle; 307 if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) { 308 // Some user handles have been added or removed, update mediaserver. 309 mEnabledCameraUsers = currentUserHandles; 310 notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, currentUserHandles); 311 } 312 } 313 314 private Set<Integer> getEnabledUserHandles(int currentUserHandle) { 315 int[] userProfiles = mUserManager.getEnabledProfileIds(currentUserHandle); 316 Set<Integer> handles = new ArraySet<>(userProfiles.length); 317 318 for (int id : userProfiles) { 319 handles.add(id); 320 } 321 322 return handles; 323 } 324 325 private void notifySwitchWithRetries(int retries) { 326 synchronized(mLock) { 327 if (mEnabledCameraUsers == null) { 328 return; 329 } 330 if (notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) { 331 retries = 0; 332 } 333 } 334 if (retries <= 0) { 335 return; 336 } 337 Slog.i(TAG, "Could not notify camera service of user switch, retrying..."); 338 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWITCH_USER, retries - 1, 0, null), 339 RETRY_DELAY_TIME); 340 } 341 342 private boolean notifyMediaserverLocked(int eventType, Set<Integer> updatedUserHandles) { 343 // Forward the user switch event to the native camera service running in the mediaserver 344 // process. 345 if (mCameraServiceRaw == null) { 346 IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME); 347 if (cameraServiceBinder == null) { 348 Slog.w(TAG, "Could not notify mediaserver, camera service not available."); 349 return false; // Camera service not active, cannot evict user clients. 350 } 351 try { 352 cameraServiceBinder.linkToDeath(this, /*flags*/ 0); 353 } catch (RemoteException e) { 354 Slog.w(TAG, "Could not link to death of native camera service"); 355 return false; 356 } 357 358 mCameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); 359 } 360 361 try { 362 mCameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles)); 363 } catch (RemoteException e) { 364 Slog.w(TAG, "Could not notify mediaserver, remote exception: " + e); 365 // Not much we can do if camera service is dead. 366 return false; 367 } 368 return true; 369 } 370 371 private void updateActivityCount(String cameraId, int newCameraState, int facing, String clientName) { 372 synchronized(mLock) { 373 // Update active camera list and notify NFC if necessary 374 boolean wasEmpty = mActiveCameraUsage.isEmpty(); 375 switch (newCameraState) { 376 case ICameraServiceProxy.CAMERA_STATE_OPEN: 377 break; 378 case ICameraServiceProxy.CAMERA_STATE_ACTIVE: 379 CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName); 380 CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent); 381 if (oldEvent != null) { 382 Slog.w(TAG, "Camera " + cameraId + " was already marked as active"); 383 oldEvent.markCompleted(); 384 mCameraUsageHistory.add(oldEvent); 385 } 386 break; 387 case ICameraServiceProxy.CAMERA_STATE_IDLE: 388 case ICameraServiceProxy.CAMERA_STATE_CLOSED: 389 CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId); 390 if (doneEvent != null) { 391 doneEvent.markCompleted(); 392 mCameraUsageHistory.add(doneEvent); 393 if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) { 394 dumpUsageEvents(); 395 } 396 } 397 break; 398 } 399 boolean isEmpty = mActiveCameraUsage.isEmpty(); 400 if ( mNotifyNfc && (wasEmpty != isEmpty) ) { 401 notifyNfcService(isEmpty); 402 } 403 } 404 } 405 406 private void notifyNfcService(boolean enablePolling) { 407 408 IBinder nfcServiceBinder = getBinderService(NFC_SERVICE_BINDER_NAME); 409 if (nfcServiceBinder == null) { 410 Slog.w(TAG, "Could not connect to NFC service to notify it of camera state"); 411 return; 412 } 413 INfcAdapter nfcAdapterRaw = INfcAdapter.Stub.asInterface(nfcServiceBinder); 414 int flags = enablePolling ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS; 415 if (DEBUG) Slog.v(TAG, "Setting NFC reader mode to flags " + flags); 416 try { 417 nfcAdapterRaw.setReaderMode(nfcInterfaceToken, null, flags, null); 418 } catch (RemoteException e) { 419 Slog.w(TAG, "Could not notify NFC service, remote exception: " + e); 420 } 421 } 422 423 private static int[] toArray(Collection<Integer> c) { 424 int len = c.size(); 425 int[] ret = new int[len]; 426 int idx = 0; 427 for (Integer i : c) { 428 ret[idx++] = i; 429 } 430 return ret; 431 } 432 433 private static String cameraStateToString(int newCameraState) { 434 switch (newCameraState) { 435 case ICameraServiceProxy.CAMERA_STATE_OPEN: return "CAMERA_STATE_OPEN"; 436 case ICameraServiceProxy.CAMERA_STATE_ACTIVE: return "CAMERA_STATE_ACTIVE"; 437 case ICameraServiceProxy.CAMERA_STATE_IDLE: return "CAMERA_STATE_IDLE"; 438 case ICameraServiceProxy.CAMERA_STATE_CLOSED: return "CAMERA_STATE_CLOSED"; 439 default: break; 440 } 441 return "CAMERA_STATE_UNKNOWN"; 442 } 443 444 private static String cameraFacingToString(int cameraFacing) { 445 switch (cameraFacing) { 446 case ICameraServiceProxy.CAMERA_FACING_BACK: return "CAMERA_FACING_BACK"; 447 case ICameraServiceProxy.CAMERA_FACING_FRONT: return "CAMERA_FACING_FRONT"; 448 case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: return "CAMERA_FACING_EXTERNAL"; 449 default: break; 450 } 451 return "CAMERA_FACING_UNKNOWN"; 452 } 453 454 } 455