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