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