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