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