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 static android.os.Build.VERSION_CODES.M; 19 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.ActivityManager; 24 import android.app.ActivityTaskManager; 25 import android.app.TaskStackListener; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.content.pm.ActivityInfo; 31 import android.content.pm.PackageManager; 32 import android.content.res.Configuration; 33 import android.hardware.CameraSessionStats; 34 import android.hardware.CameraStreamStats; 35 import android.hardware.ICameraService; 36 import android.hardware.ICameraServiceProxy; 37 import android.hardware.camera2.CameraMetadata; 38 import android.hardware.display.DisplayManager; 39 import android.media.AudioManager; 40 import android.nfc.INfcAdapter; 41 import android.os.Binder; 42 import android.os.Handler; 43 import android.os.IBinder; 44 import android.os.Message; 45 import android.os.Process; 46 import android.os.RemoteException; 47 import android.os.SystemClock; 48 import android.os.SystemProperties; 49 import android.os.UserManager; 50 import android.stats.camera.nano.CameraProtos.CameraStreamProto; 51 import android.util.ArrayMap; 52 import android.util.ArraySet; 53 import android.util.Log; 54 import android.util.Slog; 55 import android.view.Display; 56 import android.view.IDisplayWindowListener; 57 import android.view.Surface; 58 import android.view.WindowManagerGlobal; 59 60 import com.android.internal.annotations.GuardedBy; 61 import com.android.framework.protobuf.nano.MessageNano; 62 import com.android.internal.util.FrameworkStatsLog; 63 import com.android.server.LocalServices; 64 import com.android.server.ServiceThread; 65 import com.android.server.SystemService; 66 import com.android.server.wm.WindowManagerInternal; 67 68 import java.lang.annotation.Retention; 69 import java.lang.annotation.RetentionPolicy; 70 import java.util.ArrayList; 71 import java.util.Arrays; 72 import java.util.Collection; 73 import java.util.Collections; 74 import java.util.List; 75 import java.util.Map; 76 import java.util.Set; 77 import java.util.concurrent.ScheduledThreadPoolExecutor; 78 import java.util.concurrent.TimeUnit; 79 80 /** 81 * CameraServiceProxy is the system_server analog to the camera service running in cameraserver. 82 * 83 * @hide 84 */ 85 public class CameraServiceProxy extends SystemService 86 implements Handler.Callback, IBinder.DeathRecipient { 87 private static final String TAG = "CameraService_proxy"; 88 private static final boolean DEBUG = false; 89 90 /** 91 * This must match the ICameraService.aidl definition 92 */ 93 private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera"; 94 95 public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy"; 96 97 // Flags arguments to NFC adapter to enable/disable NFC 98 public static final int DISABLE_POLLING_FLAGS = 0x1000; 99 public static final int ENABLE_POLLING_FLAGS = 0x0000; 100 101 // Handler message codes 102 private static final int MSG_SWITCH_USER = 1; 103 private static final int MSG_NOTIFY_DEVICE_STATE = 2; 104 105 private static final int RETRY_DELAY_TIME = 20; //ms 106 private static final int RETRY_TIMES = 60; 107 108 @IntDef(flag = true, prefix = { "DEVICE_STATE_" }, value = { 109 ICameraService.DEVICE_STATE_BACK_COVERED, 110 ICameraService.DEVICE_STATE_FRONT_COVERED, 111 ICameraService.DEVICE_STATE_FOLDED 112 }) 113 @Retention(RetentionPolicy.SOURCE) 114 @interface DeviceStateFlags {} 115 116 // Maximum entries to keep in usage history before dumping out 117 private static final int MAX_USAGE_HISTORY = 20; 118 // Number of stream statistics being dumped for each camera session 119 // Must be equal to number of CameraStreamProto in CameraActionEvent 120 private static final int MAX_STREAM_STATISTICS = 5; 121 122 private final Context mContext; 123 private final ServiceThread mHandlerThread; 124 private final Handler mHandler; 125 private UserManager mUserManager; 126 127 private final Object mLock = new Object(); 128 private Set<Integer> mEnabledCameraUsers; 129 private int mLastUser; 130 // The current set of device state flags. May be different from mLastReportedDeviceState if the 131 // native camera service has not been notified of the change. 132 @GuardedBy("mLock") 133 @DeviceStateFlags 134 private int mDeviceState; 135 // The most recent device state flags reported to the native camera server. 136 @GuardedBy("mLock") 137 @DeviceStateFlags 138 private int mLastReportedDeviceState; 139 140 private ICameraService mCameraServiceRaw; 141 142 // Map of currently active camera IDs 143 private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>(); 144 private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>(); 145 146 private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc"; 147 private static final String NFC_SERVICE_BINDER_NAME = "nfc"; 148 private static final IBinder nfcInterfaceToken = new Binder(); 149 150 private final boolean mNotifyNfc; 151 152 private ScheduledThreadPoolExecutor mLogWriterService = new ScheduledThreadPoolExecutor( 153 /*corePoolSize*/ 1); 154 155 /** 156 * Structure to track camera usage 157 */ 158 private static class CameraUsageEvent { 159 public final String mCameraId; 160 public final int mCameraFacing; 161 public final String mClientName; 162 public final int mAPILevel; 163 public final boolean mIsNdk; 164 public final int mAction; 165 public final int mLatencyMs; 166 public final int mOperatingMode; 167 168 private boolean mCompleted; 169 public int mInternalReconfigure; 170 public long mRequestCount; 171 public long mResultErrorCount; 172 public boolean mDeviceError; 173 public List<CameraStreamStats> mStreamStats; 174 private long mDurationOrStartTimeMs; // Either start time, or duration once completed 175 CameraUsageEvent(String cameraId, int facing, String clientName, int apiLevel, boolean isNdk, int action, int latencyMs, int operatingMode)176 CameraUsageEvent(String cameraId, int facing, String clientName, int apiLevel, 177 boolean isNdk, int action, int latencyMs, int operatingMode) { 178 mCameraId = cameraId; 179 mCameraFacing = facing; 180 mClientName = clientName; 181 mAPILevel = apiLevel; 182 mDurationOrStartTimeMs = SystemClock.elapsedRealtime(); 183 mCompleted = false; 184 mIsNdk = isNdk; 185 mAction = action; 186 mLatencyMs = latencyMs; 187 mOperatingMode = operatingMode; 188 } 189 markCompleted(int internalReconfigure, long requestCount, long resultErrorCount, boolean deviceError, List<CameraStreamStats> streamStats)190 public void markCompleted(int internalReconfigure, long requestCount, 191 long resultErrorCount, boolean deviceError, 192 List<CameraStreamStats> streamStats) { 193 if (mCompleted) { 194 return; 195 } 196 mCompleted = true; 197 mDurationOrStartTimeMs = SystemClock.elapsedRealtime() - mDurationOrStartTimeMs; 198 mInternalReconfigure = internalReconfigure; 199 mRequestCount = requestCount; 200 mResultErrorCount = resultErrorCount; 201 mDeviceError = deviceError; 202 mStreamStats = streamStats; 203 if (CameraServiceProxy.DEBUG) { 204 Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) + 205 " was in use by " + mClientName + " for " + 206 mDurationOrStartTimeMs + " ms"); 207 } 208 } 209 210 /** 211 * Return duration of camera usage event, or 0 if the event is not done 212 */ getDuration()213 public long getDuration() { 214 return mCompleted ? mDurationOrStartTimeMs : 0; 215 } 216 } 217 218 private final class DisplayWindowListener extends IDisplayWindowListener.Stub { 219 220 @Override onDisplayConfigurationChanged(int displayId, Configuration newConfig)221 public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { 222 ICameraService cs = getCameraServiceRawLocked(); 223 if (cs == null) return; 224 225 try { 226 cs.notifyDisplayConfigurationChange(); 227 } catch (RemoteException e) { 228 Slog.w(TAG, "Could not notify cameraserver, remote exception: " + e); 229 // Not much we can do if camera service is dead. 230 } 231 } 232 233 @Override onDisplayAdded(int displayId)234 public void onDisplayAdded(int displayId) { } 235 236 @Override onDisplayRemoved(int displayId)237 public void onDisplayRemoved(int displayId) { } 238 239 @Override onFixedRotationStarted(int displayId, int newRotation)240 public void onFixedRotationStarted(int displayId, int newRotation) { } 241 242 @Override onFixedRotationFinished(int displayId)243 public void onFixedRotationFinished(int displayId) { } 244 } 245 246 247 private final DisplayWindowListener mDisplayWindowListener = new DisplayWindowListener(); 248 249 private final TaskStateHandler mTaskStackListener = new TaskStateHandler(); 250 251 private final class TaskInfo { 252 private int frontTaskId; 253 private boolean isResizeable; 254 private boolean isFixedOrientationLandscape; 255 private boolean isFixedOrientationPortrait; 256 private int displayId; 257 } 258 259 private final class TaskStateHandler extends TaskStackListener { 260 private final Object mMapLock = new Object(); 261 262 // maps the package name to its corresponding current top level task id 263 @GuardedBy("mMapLock") 264 private final ArrayMap<String, TaskInfo> mTaskInfoMap = new ArrayMap<>(); 265 266 @Override onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)267 public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) { 268 synchronized (mMapLock) { 269 TaskInfo info = new TaskInfo(); 270 info.frontTaskId = taskInfo.taskId; 271 info.isResizeable = taskInfo.isResizeable; 272 info.displayId = taskInfo.displayId; 273 info.isFixedOrientationLandscape = ActivityInfo.isFixedOrientationLandscape( 274 taskInfo.topActivityInfo.screenOrientation); 275 info.isFixedOrientationPortrait = ActivityInfo.isFixedOrientationPortrait( 276 taskInfo.topActivityInfo.screenOrientation); 277 mTaskInfoMap.put(taskInfo.topActivityInfo.packageName, info); 278 } 279 } 280 281 @Override onTaskRemoved(int taskId)282 public void onTaskRemoved(int taskId) { 283 synchronized (mMapLock) { 284 for (Map.Entry<String, TaskInfo> entry : mTaskInfoMap.entrySet()){ 285 if (entry.getValue().frontTaskId == taskId) { 286 mTaskInfoMap.remove(entry.getKey()); 287 break; 288 } 289 } 290 } 291 } 292 getFrontTaskInfo(String packageName)293 public @Nullable TaskInfo getFrontTaskInfo(String packageName) { 294 synchronized (mMapLock) { 295 if (mTaskInfoMap.containsKey(packageName)) { 296 return mTaskInfoMap.get(packageName); 297 } 298 } 299 300 Log.e(TAG, "Top task with package name: " + packageName + " not found!"); 301 return null; 302 } 303 }; 304 305 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 306 @Override 307 public void onReceive(Context context, Intent intent) { 308 final String action = intent.getAction(); 309 if (action == null) return; 310 311 switch (action) { 312 case Intent.ACTION_USER_ADDED: 313 case Intent.ACTION_USER_REMOVED: 314 case Intent.ACTION_USER_INFO_CHANGED: 315 case Intent.ACTION_MANAGED_PROFILE_ADDED: 316 case Intent.ACTION_MANAGED_PROFILE_REMOVED: 317 synchronized(mLock) { 318 // Return immediately if we haven't seen any users start yet 319 if (mEnabledCameraUsers == null) return; 320 switchUserLocked(mLastUser); 321 } 322 break; 323 default: 324 break; // do nothing 325 } 326 327 } 328 }; 329 330 private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() { 331 private boolean isMOrBelow(Context ctx, String packageName) { 332 try { 333 return ctx.getPackageManager().getPackageInfo( 334 packageName, 0).applicationInfo.targetSdkVersion <= M; 335 } catch (PackageManager.NameNotFoundException e) { 336 Slog.e(TAG,"Package name not found!"); 337 } 338 return false; 339 } 340 341 /** 342 * Gets whether crop-rotate-scale is needed. 343 */ 344 private boolean getNeedCropRotateScale(@NonNull Context ctx, @NonNull String packageName, 345 @Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing) { 346 if (taskInfo == null) { 347 return false; 348 } 349 350 // External cameras do not need crop-rotate-scale. 351 if (lensFacing != CameraMetadata.LENS_FACING_FRONT 352 && lensFacing != CameraMetadata.LENS_FACING_BACK) { 353 Log.v(TAG, "lensFacing=" + lensFacing + ". Crop-rotate-scale is disabled."); 354 return false; 355 } 356 357 // Only enable the crop-rotate-scale workaround if the app targets M or below and is not 358 // resizeable. 359 if (!isMOrBelow(ctx, packageName) && taskInfo.isResizeable) { 360 Slog.v(TAG, 361 "The activity is N or above and claims to support resizeable-activity. " 362 + "Crop-rotate-scale is disabled."); 363 return false; 364 } 365 366 DisplayManager displayManager = ctx.getSystemService(DisplayManager.class); 367 Display display = displayManager.getDisplay(taskInfo.displayId); 368 int rotation = display.getRotation(); 369 int rotationDegree = 0; 370 switch (rotation) { 371 case Surface.ROTATION_0: 372 rotationDegree = 0; 373 break; 374 case Surface.ROTATION_90: 375 rotationDegree = 90; 376 break; 377 case Surface.ROTATION_180: 378 rotationDegree = 180; 379 break; 380 case Surface.ROTATION_270: 381 rotationDegree = 270; 382 break; 383 } 384 385 // Here we only need to know whether the camera is landscape or portrait. Therefore we 386 // don't need to consider whether it is a front or back camera. The formula works for 387 // both. 388 boolean landscapeCamera = ((rotationDegree + sensorOrientation) % 180 == 0); 389 Slog.v(TAG, 390 "Display.getRotation()=" + rotationDegree 391 + " CameraCharacteristics.SENSOR_ORIENTATION=" + sensorOrientation 392 + " isFixedOrientationPortrait=" + taskInfo.isFixedOrientationPortrait 393 + " isFixedOrientationLandscape=" + 394 taskInfo.isFixedOrientationLandscape); 395 // We need to do crop-rotate-scale when camera is landscape and activity is portrait or 396 // vice versa. 397 return (taskInfo.isFixedOrientationPortrait && landscapeCamera) 398 || (taskInfo.isFixedOrientationLandscape && !landscapeCamera); 399 } 400 401 @Override 402 public boolean isRotateAndCropOverrideNeeded(String packageName, int sensorOrientation, 403 int lensFacing) { 404 if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { 405 Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " + 406 " camera service UID!"); 407 return false; 408 } 409 410 // TODO: Modify the sensor orientation in camera characteristics along with any 3A 411 // regions in capture requests/results to account for thea physical rotation. The 412 // former is somewhat tricky as it assumes that camera clients always check for the 413 // current value by retrieving the camera characteristics from the camera device. 414 return getNeedCropRotateScale(mContext, packageName, 415 mTaskStackListener.getFrontTaskInfo(packageName), sensorOrientation, 416 lensFacing); 417 } 418 419 @Override 420 public void pingForUserUpdate() { 421 if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { 422 Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " + 423 " camera service UID!"); 424 return; 425 } 426 notifySwitchWithRetries(RETRY_TIMES); 427 notifyDeviceStateWithRetries(RETRY_TIMES); 428 } 429 430 @Override 431 public void notifyCameraState(CameraSessionStats cameraState) { 432 if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { 433 Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " + 434 " camera service UID!"); 435 return; 436 } 437 String state = cameraStateToString(cameraState.getNewCameraState()); 438 String facingStr = cameraFacingToString(cameraState.getFacing()); 439 if (DEBUG) { 440 Slog.v(TAG, "Camera " + cameraState.getCameraId() 441 + " facing " + facingStr + " state now " + state 442 + " for client " + cameraState.getClientName() 443 + " API Level " + cameraState.getApiLevel()); 444 } 445 446 updateActivityCount(cameraState); 447 } 448 }; 449 CameraServiceProxy(Context context)450 public CameraServiceProxy(Context context) { 451 super(context); 452 mContext = context; 453 mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY, /*allowTo*/false); 454 mHandlerThread.start(); 455 mHandler = new Handler(mHandlerThread.getLooper(), this); 456 457 mNotifyNfc = SystemProperties.getInt(NFC_NOTIFICATION_PROP, 0) > 0; 458 if (DEBUG) Slog.v(TAG, "Notify NFC behavior is " + (mNotifyNfc ? "active" : "disabled")); 459 // Don't keep any extra logging threads if not needed 460 mLogWriterService.setKeepAliveTime(1, TimeUnit.SECONDS); 461 mLogWriterService.allowCoreThreadTimeOut(true); 462 } 463 464 /** 465 * Sets the device state bits set within {@code deviceStateFlags} leaving all other bits the 466 * same. 467 * <p> 468 * Calling requires permission {@link android.Manifest.permission#CAMERA_SEND_SYSTEM_EVENTS}. 469 * 470 * @param deviceStateFlags a bitmask of the device state bits that should be set. 471 * 472 * @see #clearDeviceStateFlags(int) 473 */ setDeviceStateFlags(@eviceStateFlags int deviceStateFlags)474 public void setDeviceStateFlags(@DeviceStateFlags int deviceStateFlags) { 475 synchronized (mLock) { 476 mHandler.removeMessages(MSG_NOTIFY_DEVICE_STATE); 477 mDeviceState |= deviceStateFlags; 478 if (mDeviceState != mLastReportedDeviceState) { 479 notifyDeviceStateWithRetriesLocked(RETRY_TIMES); 480 } 481 } 482 } 483 484 /** 485 * Clears the device state bits set within {@code deviceStateFlags} leaving all other bits the 486 * same. 487 * <p> 488 * Calling requires permission {@link android.Manifest.permission#CAMERA_SEND_SYSTEM_EVENTS}. 489 * 490 * @param deviceStateFlags a bitmask of the device state bits that should be cleared. 491 * 492 * @see #setDeviceStateFlags(int) 493 */ clearDeviceStateFlags(@eviceStateFlags int deviceStateFlags)494 public void clearDeviceStateFlags(@DeviceStateFlags int deviceStateFlags) { 495 synchronized (mLock) { 496 mHandler.removeMessages(MSG_NOTIFY_DEVICE_STATE); 497 mDeviceState &= ~deviceStateFlags; 498 if (mDeviceState != mLastReportedDeviceState) { 499 notifyDeviceStateWithRetriesLocked(RETRY_TIMES); 500 } 501 } 502 } 503 504 @Override handleMessage(Message msg)505 public boolean handleMessage(Message msg) { 506 switch(msg.what) { 507 case MSG_SWITCH_USER: { 508 notifySwitchWithRetries(msg.arg1); 509 } break; 510 case MSG_NOTIFY_DEVICE_STATE: { 511 notifyDeviceStateWithRetries(msg.arg1); 512 } break; 513 default: { 514 Slog.e(TAG, "CameraServiceProxy error, invalid message: " + msg.what); 515 } break; 516 } 517 return true; 518 } 519 520 @Override onStart()521 public void onStart() { 522 mUserManager = UserManager.get(mContext); 523 if (mUserManager == null) { 524 // Should never see this unless someone messes up the SystemServer service boot order. 525 throw new IllegalStateException("UserManagerService must start before" + 526 " CameraServiceProxy!"); 527 } 528 529 IntentFilter filter = new IntentFilter(); 530 filter.addAction(Intent.ACTION_USER_ADDED); 531 filter.addAction(Intent.ACTION_USER_REMOVED); 532 filter.addAction(Intent.ACTION_USER_INFO_CHANGED); 533 filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 534 filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 535 mContext.registerReceiver(mIntentReceiver, filter); 536 537 publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy); 538 publishLocalService(CameraServiceProxy.class, this); 539 } 540 541 @Override onBootPhase(int phase)542 public void onBootPhase(int phase) { 543 if (phase == PHASE_BOOT_COMPLETED) { 544 CameraStatsJobService.schedule(mContext); 545 546 try { 547 ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener); 548 } catch (RemoteException e) { 549 Log.e(TAG, "Failed to register task stack listener!"); 550 } 551 552 try { 553 WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener( 554 mDisplayWindowListener); 555 } catch (RemoteException e) { 556 Log.e(TAG, "Failed to register display window listener!"); 557 } 558 } 559 } 560 561 @Override onUserStarting(@onNull TargetUser user)562 public void onUserStarting(@NonNull TargetUser user) { 563 synchronized(mLock) { 564 if (mEnabledCameraUsers == null) { 565 // Initialize cameraserver, or update cameraserver if we are recovering 566 // from a crash. 567 switchUserLocked(user.getUserIdentifier()); 568 } 569 } 570 } 571 572 @Override onUserSwitching(@ullable TargetUser from, @NonNull TargetUser to)573 public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { 574 synchronized(mLock) { 575 switchUserLocked(to.getUserIdentifier()); 576 } 577 } 578 579 /** 580 * Handle the death of the native camera service 581 */ 582 @Override binderDied()583 public void binderDied() { 584 if (DEBUG) Slog.w(TAG, "Native camera service has died"); 585 synchronized(mLock) { 586 mCameraServiceRaw = null; 587 588 // All cameras reset to idle on camera service death 589 boolean wasEmpty = mActiveCameraUsage.isEmpty(); 590 mActiveCameraUsage.clear(); 591 592 if ( mNotifyNfc && !wasEmpty ) { 593 notifyNfcService(/*enablePolling*/ true); 594 } 595 } 596 } 597 598 private class EventWriterTask implements Runnable { 599 private ArrayList<CameraUsageEvent> mEventList; 600 private static final long WRITER_SLEEP_MS = 100; 601 EventWriterTask(ArrayList<CameraUsageEvent> eventList)602 public EventWriterTask(ArrayList<CameraUsageEvent> eventList) { 603 mEventList = eventList; 604 } 605 606 @Override run()607 public void run() { 608 if (mEventList != null) { 609 for (CameraUsageEvent event : mEventList) { 610 logCameraUsageEvent(event); 611 try { 612 Thread.sleep(WRITER_SLEEP_MS); 613 } catch (InterruptedException e) {} 614 } 615 mEventList.clear(); 616 } 617 } 618 619 /** 620 * Write camera usage events to stats log. 621 * Package-private 622 */ logCameraUsageEvent(CameraUsageEvent e)623 private void logCameraUsageEvent(CameraUsageEvent e) { 624 int facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN; 625 switch(e.mCameraFacing) { 626 case CameraSessionStats.CAMERA_FACING_BACK: 627 facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__BACK; 628 break; 629 case CameraSessionStats.CAMERA_FACING_FRONT: 630 facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__FRONT; 631 break; 632 case CameraSessionStats.CAMERA_FACING_EXTERNAL: 633 facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL; 634 break; 635 default: 636 Slog.w(TAG, "Unknown camera facing: " + e.mCameraFacing); 637 } 638 639 int streamCount = 0; 640 if (e.mStreamStats != null) { 641 streamCount = e.mStreamStats.size(); 642 } 643 if (CameraServiceProxy.DEBUG) { 644 Slog.v(TAG, "CAMERA_ACTION_EVENT: action " + e.mAction 645 + " clientName " + e.mClientName 646 + ", duration " + e.getDuration() 647 + ", APILevel " + e.mAPILevel 648 + ", cameraId " + e.mCameraId 649 + ", facing " + facing 650 + ", isNdk " + e.mIsNdk 651 + ", latencyMs " + e.mLatencyMs 652 + ", operatingMode " + e.mOperatingMode 653 + ", internalReconfigure " + e.mInternalReconfigure 654 + ", requestCount " + e.mRequestCount 655 + ", resultErrorCount " + e.mResultErrorCount 656 + ", deviceError " + e.mDeviceError 657 + ", streamCount is " + streamCount); 658 } 659 // Convert from CameraStreamStats to CameraStreamProto 660 CameraStreamProto[] streamProtos = new CameraStreamProto[MAX_STREAM_STATISTICS]; 661 for (int i = 0; i < MAX_STREAM_STATISTICS; i++) { 662 streamProtos[i] = new CameraStreamProto(); 663 if (i < streamCount) { 664 CameraStreamStats streamStats = e.mStreamStats.get(i); 665 streamProtos[i].width = streamStats.getWidth(); 666 streamProtos[i].height = streamStats.getHeight(); 667 streamProtos[i].format = streamStats.getFormat(); 668 streamProtos[i].dataSpace = streamStats.getDataSpace(); 669 streamProtos[i].usage = streamStats.getUsage(); 670 streamProtos[i].requestCount = streamStats.getRequestCount(); 671 streamProtos[i].errorCount = streamStats.getErrorCount(); 672 streamProtos[i].firstCaptureLatencyMillis = streamStats.getStartLatencyMs(); 673 streamProtos[i].maxHalBuffers = streamStats.getMaxHalBuffers(); 674 streamProtos[i].maxAppBuffers = streamStats.getMaxAppBuffers(); 675 streamProtos[i].histogramType = streamStats.getHistogramType(); 676 streamProtos[i].histogramBins = streamStats.getHistogramBins(); 677 streamProtos[i].histogramCounts = streamStats.getHistogramCounts(); 678 679 if (CameraServiceProxy.DEBUG) { 680 String histogramTypeName = 681 cameraHistogramTypeToString(streamProtos[i].histogramType); 682 Slog.v(TAG, "Stream " + i + ": width " + streamProtos[i].width 683 + ", height " + streamProtos[i].height 684 + ", format " + streamProtos[i].format 685 + ", dataSpace " + streamProtos[i].dataSpace 686 + ", usage " + streamProtos[i].usage 687 + ", requestCount " + streamProtos[i].requestCount 688 + ", errorCount " + streamProtos[i].errorCount 689 + ", firstCaptureLatencyMillis " 690 + streamProtos[i].firstCaptureLatencyMillis 691 + ", maxHalBuffers " + streamProtos[i].maxHalBuffers 692 + ", maxAppBuffers " + streamProtos[i].maxAppBuffers 693 + ", histogramType " + histogramTypeName 694 + ", histogramBins " 695 + Arrays.toString(streamProtos[i].histogramBins) 696 + ", histogramCounts " 697 + Arrays.toString(streamProtos[i].histogramCounts)); 698 } 699 } 700 } 701 FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_ACTION_EVENT, e.getDuration(), 702 e.mAPILevel, e.mClientName, facing, e.mCameraId, e.mAction, e.mIsNdk, 703 e.mLatencyMs, e.mOperatingMode, e.mInternalReconfigure, 704 e.mRequestCount, e.mResultErrorCount, e.mDeviceError, 705 streamCount, MessageNano.toByteArray(streamProtos[0]), 706 MessageNano.toByteArray(streamProtos[1]), 707 MessageNano.toByteArray(streamProtos[2]), 708 MessageNano.toByteArray(streamProtos[3]), 709 MessageNano.toByteArray(streamProtos[4])); 710 } 711 } 712 713 /** 714 * Dump camera usage events to log. 715 * Package-private 716 */ dumpUsageEvents()717 void dumpUsageEvents() { 718 synchronized(mLock) { 719 // Randomize order of events so that it's not meaningful 720 Collections.shuffle(mCameraUsageHistory); 721 mLogWriterService.execute(new EventWriterTask( 722 new ArrayList<CameraUsageEvent>(mCameraUsageHistory))); 723 724 mCameraUsageHistory.clear(); 725 } 726 final long ident = Binder.clearCallingIdentity(); 727 try { 728 CameraStatsJobService.schedule(mContext); 729 } finally { 730 Binder.restoreCallingIdentity(ident); 731 } 732 } 733 734 @Nullable getCameraServiceRawLocked()735 private ICameraService getCameraServiceRawLocked() { 736 if (mCameraServiceRaw == null) { 737 IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME); 738 if (cameraServiceBinder == null) { 739 return null; 740 } 741 try { 742 cameraServiceBinder.linkToDeath(this, /*flags*/ 0); 743 } catch (RemoteException e) { 744 Slog.w(TAG, "Could not link to death of native camera service"); 745 return null; 746 } 747 748 mCameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder); 749 } 750 return mCameraServiceRaw; 751 } 752 switchUserLocked(int userHandle)753 private void switchUserLocked(int userHandle) { 754 Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle); 755 mLastUser = userHandle; 756 if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) { 757 // Some user handles have been added or removed, update cameraserver. 758 mEnabledCameraUsers = currentUserHandles; 759 notifySwitchWithRetriesLocked(RETRY_TIMES); 760 } 761 } 762 getEnabledUserHandles(int currentUserHandle)763 private Set<Integer> getEnabledUserHandles(int currentUserHandle) { 764 int[] userProfiles = mUserManager.getEnabledProfileIds(currentUserHandle); 765 Set<Integer> handles = new ArraySet<>(userProfiles.length); 766 767 for (int id : userProfiles) { 768 handles.add(id); 769 } 770 771 return handles; 772 } 773 notifySwitchWithRetries(int retries)774 private void notifySwitchWithRetries(int retries) { 775 synchronized(mLock) { 776 notifySwitchWithRetriesLocked(retries); 777 } 778 } 779 notifySwitchWithRetriesLocked(int retries)780 private void notifySwitchWithRetriesLocked(int retries) { 781 if (mEnabledCameraUsers == null) { 782 return; 783 } 784 if (notifyCameraserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) { 785 retries = 0; 786 } 787 if (retries <= 0) { 788 return; 789 } 790 Slog.i(TAG, "Could not notify camera service of user switch, retrying..."); 791 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWITCH_USER, retries - 1, 0, null), 792 RETRY_DELAY_TIME); 793 } 794 notifyCameraserverLocked(int eventType, Set<Integer> updatedUserHandles)795 private boolean notifyCameraserverLocked(int eventType, Set<Integer> updatedUserHandles) { 796 // Forward the user switch event to the native camera service running in the cameraserver 797 // process. 798 ICameraService cameraService = getCameraServiceRawLocked(); 799 if (cameraService == null) { 800 Slog.w(TAG, "Could not notify cameraserver, camera service not available."); 801 return false; 802 } 803 804 try { 805 mCameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles)); 806 } catch (RemoteException e) { 807 Slog.w(TAG, "Could not notify cameraserver, remote exception: " + e); 808 // Not much we can do if camera service is dead. 809 return false; 810 } 811 return true; 812 } 813 notifyDeviceStateWithRetries(int retries)814 private void notifyDeviceStateWithRetries(int retries) { 815 synchronized (mLock) { 816 notifyDeviceStateWithRetriesLocked(retries); 817 } 818 } 819 notifyDeviceStateWithRetriesLocked(int retries)820 private void notifyDeviceStateWithRetriesLocked(int retries) { 821 if (notifyDeviceStateChangeLocked(mDeviceState)) { 822 return; 823 } 824 if (retries <= 0) { 825 return; 826 } 827 Slog.i(TAG, "Could not notify camera service of device state change, retrying..."); 828 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_NOTIFY_DEVICE_STATE, retries - 1, 829 0, null), RETRY_DELAY_TIME); 830 } 831 notifyDeviceStateChangeLocked(@eviceStateFlags int deviceState)832 private boolean notifyDeviceStateChangeLocked(@DeviceStateFlags int deviceState) { 833 // Forward the state to the native camera service running in the cameraserver process. 834 ICameraService cameraService = getCameraServiceRawLocked(); 835 if (cameraService == null) { 836 Slog.w(TAG, "Could not notify cameraserver, camera service not available."); 837 return false; 838 } 839 840 try { 841 mCameraServiceRaw.notifyDeviceStateChange(deviceState); 842 } catch (RemoteException e) { 843 Slog.w(TAG, "Could not notify cameraserver, remote exception: " + e); 844 // Not much we can do if camera service is dead. 845 return false; 846 } 847 mLastReportedDeviceState = deviceState; 848 return true; 849 } 850 updateActivityCount(CameraSessionStats cameraState)851 private void updateActivityCount(CameraSessionStats cameraState) { 852 String cameraId = cameraState.getCameraId(); 853 int newCameraState = cameraState.getNewCameraState(); 854 int facing = cameraState.getFacing(); 855 String clientName = cameraState.getClientName(); 856 int apiLevel = cameraState.getApiLevel(); 857 boolean isNdk = cameraState.isNdk(); 858 int sessionType = cameraState.getSessionType(); 859 int internalReconfigureCount = cameraState.getInternalReconfigureCount(); 860 int latencyMs = cameraState.getLatencyMs(); 861 long requestCount = cameraState.getRequestCount(); 862 long resultErrorCount = cameraState.getResultErrorCount(); 863 boolean deviceError = cameraState.getDeviceErrorFlag(); 864 List<CameraStreamStats> streamStats = cameraState.getStreamStats(); 865 synchronized(mLock) { 866 // Update active camera list and notify NFC if necessary 867 boolean wasEmpty = mActiveCameraUsage.isEmpty(); 868 switch (newCameraState) { 869 case CameraSessionStats.CAMERA_STATE_OPEN: 870 // Notify the audio subsystem about the facing of the most-recently opened 871 // camera This can be used to select the best audio tuning in case video 872 // recording with that camera will happen. Since only open events are used, if 873 // multiple cameras are opened at once, the one opened last will be used to 874 // select audio tuning. 875 AudioManager audioManager = getContext().getSystemService(AudioManager.class); 876 if (audioManager != null) { 877 // Map external to front for audio tuning purposes 878 String facingStr = (facing == CameraSessionStats.CAMERA_FACING_BACK) ? 879 "back" : "front"; 880 String facingParameter = "cameraFacing=" + facingStr; 881 audioManager.setParameters(facingParameter); 882 } 883 CameraUsageEvent openEvent = new CameraUsageEvent( 884 cameraId, facing, clientName, apiLevel, isNdk, 885 FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__OPEN, 886 latencyMs, sessionType); 887 mCameraUsageHistory.add(openEvent); 888 break; 889 case CameraSessionStats.CAMERA_STATE_ACTIVE: 890 // Check current active camera IDs to see if this package is already talking to 891 // some camera 892 boolean alreadyActivePackage = false; 893 for (int i = 0; i < mActiveCameraUsage.size(); i++) { 894 if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) { 895 alreadyActivePackage = true; 896 break; 897 } 898 } 899 // If not already active, notify window manager about this new package using a 900 // camera 901 if (!alreadyActivePackage) { 902 WindowManagerInternal wmi = 903 LocalServices.getService(WindowManagerInternal.class); 904 wmi.addNonHighRefreshRatePackage(clientName); 905 } 906 907 // Update activity events 908 CameraUsageEvent newEvent = new CameraUsageEvent( 909 cameraId, facing, clientName, apiLevel, isNdk, 910 FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__SESSION, 911 latencyMs, sessionType); 912 CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent); 913 if (oldEvent != null) { 914 Slog.w(TAG, "Camera " + cameraId + " was already marked as active"); 915 oldEvent.markCompleted(/*internalReconfigure*/0, /*requestCount*/0, 916 /*resultErrorCount*/0, /*deviceError*/false, streamStats); 917 mCameraUsageHistory.add(oldEvent); 918 } 919 break; 920 case CameraSessionStats.CAMERA_STATE_IDLE: 921 case CameraSessionStats.CAMERA_STATE_CLOSED: 922 CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId); 923 if (doneEvent != null) { 924 925 doneEvent.markCompleted(internalReconfigureCount, requestCount, 926 resultErrorCount, deviceError, streamStats); 927 mCameraUsageHistory.add(doneEvent); 928 929 // Check current active camera IDs to see if this package is still 930 // talking to some camera 931 boolean stillActivePackage = false; 932 for (int i = 0; i < mActiveCameraUsage.size(); i++) { 933 if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) { 934 stillActivePackage = true; 935 break; 936 } 937 } 938 // If not longer active, notify window manager about this package being done 939 // with camera 940 if (!stillActivePackage) { 941 WindowManagerInternal wmi = 942 LocalServices.getService(WindowManagerInternal.class); 943 wmi.removeNonHighRefreshRatePackage(clientName); 944 } 945 } 946 947 if (newCameraState == CameraSessionStats.CAMERA_STATE_CLOSED) { 948 CameraUsageEvent closeEvent = new CameraUsageEvent( 949 cameraId, facing, clientName, apiLevel, isNdk, 950 FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__CLOSE, 951 latencyMs, sessionType); 952 mCameraUsageHistory.add(closeEvent); 953 } 954 955 if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) { 956 dumpUsageEvents(); 957 } 958 959 break; 960 } 961 boolean isEmpty = mActiveCameraUsage.isEmpty(); 962 if ( mNotifyNfc && (wasEmpty != isEmpty) ) { 963 notifyNfcService(isEmpty); 964 } 965 } 966 } 967 notifyNfcService(boolean enablePolling)968 private void notifyNfcService(boolean enablePolling) { 969 970 IBinder nfcServiceBinder = getBinderService(NFC_SERVICE_BINDER_NAME); 971 if (nfcServiceBinder == null) { 972 Slog.w(TAG, "Could not connect to NFC service to notify it of camera state"); 973 return; 974 } 975 INfcAdapter nfcAdapterRaw = INfcAdapter.Stub.asInterface(nfcServiceBinder); 976 int flags = enablePolling ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS; 977 if (DEBUG) Slog.v(TAG, "Setting NFC reader mode to flags " + flags); 978 try { 979 nfcAdapterRaw.setReaderMode(nfcInterfaceToken, null, flags, null); 980 } catch (RemoteException e) { 981 Slog.w(TAG, "Could not notify NFC service, remote exception: " + e); 982 } 983 } 984 toArray(Collection<Integer> c)985 private static int[] toArray(Collection<Integer> c) { 986 int len = c.size(); 987 int[] ret = new int[len]; 988 int idx = 0; 989 for (Integer i : c) { 990 ret[idx++] = i; 991 } 992 return ret; 993 } 994 cameraStateToString(int newCameraState)995 private static String cameraStateToString(int newCameraState) { 996 switch (newCameraState) { 997 case CameraSessionStats.CAMERA_STATE_OPEN: return "CAMERA_STATE_OPEN"; 998 case CameraSessionStats.CAMERA_STATE_ACTIVE: return "CAMERA_STATE_ACTIVE"; 999 case CameraSessionStats.CAMERA_STATE_IDLE: return "CAMERA_STATE_IDLE"; 1000 case CameraSessionStats.CAMERA_STATE_CLOSED: return "CAMERA_STATE_CLOSED"; 1001 default: break; 1002 } 1003 return "CAMERA_STATE_UNKNOWN"; 1004 } 1005 cameraFacingToString(int cameraFacing)1006 private static String cameraFacingToString(int cameraFacing) { 1007 switch (cameraFacing) { 1008 case CameraSessionStats.CAMERA_FACING_BACK: return "CAMERA_FACING_BACK"; 1009 case CameraSessionStats.CAMERA_FACING_FRONT: return "CAMERA_FACING_FRONT"; 1010 case CameraSessionStats.CAMERA_FACING_EXTERNAL: return "CAMERA_FACING_EXTERNAL"; 1011 default: break; 1012 } 1013 return "CAMERA_FACING_UNKNOWN"; 1014 } 1015 cameraHistogramTypeToString(int cameraHistogramType)1016 private static String cameraHistogramTypeToString(int cameraHistogramType) { 1017 switch (cameraHistogramType) { 1018 case CameraStreamStats.HISTOGRAM_TYPE_CAPTURE_LATENCY: 1019 return "HISTOGRAM_TYPE_CAPTURE_LATENCY"; 1020 default: 1021 break; 1022 } 1023 return "HISTOGRAM_TYPE_UNKNOWN"; 1024 } 1025 1026 } 1027