diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2020-11-19 18:22:50 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-11-19 18:22:50 +0000 |
commit | 1c1acd45d03baf18ab0f2c1fa50d52504bf37c91 (patch) | |
tree | 29f9d7b2aee7d3cde9187abb4f872fa619985e3b | |
parent | 7a9ec89870da4debcfa3fa04a03ba0c24ca9cdc2 (diff) | |
parent | b2443990e9d4689450bf5e42b9975ac615a23716 (diff) |
Merge "Camera: Enhance camera atoms for system health"
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | cmds/statsd/src/atoms.proto | 57 | ||||
-rw-r--r-- | config/preloaded-classes | 1 | ||||
-rw-r--r-- | core/java/android/hardware/CameraSessionStats.java | 202 | ||||
-rw-r--r-- | core/java/android/hardware/CameraStreamStats.java | 169 | ||||
-rw-r--r-- | core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java | 3 | ||||
-rw-r--r-- | core/java/android/hardware/camera2/impl/CameraDeviceImpl.java | 17 | ||||
-rw-r--r-- | core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java | 6 | ||||
-rw-r--r-- | core/proto/android/stats/camera/Android.bp | 33 | ||||
-rw-r--r-- | core/proto/android/stats/camera/camera.proto | 44 | ||||
-rw-r--r-- | core/proto/android/stats/camera/jarjar-rules.txt | 1 | ||||
-rw-r--r-- | services/core/java/com/android/server/camera/CameraServiceProxy.java | 255 |
12 files changed, 698 insertions, 91 deletions
diff --git a/Android.bp b/Android.bp index aa94d2236084..8164d6a477e4 100644 --- a/Android.bp +++ b/Android.bp @@ -528,6 +528,7 @@ java_library { "android.hardware.vibrator-V1.3-java", "android.system.keystore2-java", "android.system.suspend.control.internal-java", + "cameraprotosnano", "devicepolicyprotosnano", "com.android.sysprop.apex", diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index a9037701fa01..84ad01956111 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -42,6 +42,7 @@ import "frameworks/base/core/proto/android/server/job/enums.proto"; import "frameworks/base/core/proto/android/server/location/enums.proto"; import "frameworks/base/core/proto/android/service/procstats_enum.proto"; import "frameworks/base/core/proto/android/service/usb.proto"; +import "frameworks/base/core/proto/android/stats/camera/camera.proto"; import "frameworks/base/core/proto/android/stats/connectivity/network_stack.proto"; import "frameworks/base/core/proto/android/stats/connectivity/tethering.proto"; import "frameworks/base/core/proto/android/stats/dnsresolver/dns_resolver.proto"; @@ -9950,10 +9951,12 @@ message DisplayJankReported { * frameworks/base/services/core/java/com/android/server/camera/CameraServiceProxy.java */ message CameraActionEvent { - // Camera session duration + // Camera session duration in milliseconds if action is SESSION. + // 0 if action is OPEN or CLOSE. optional int64 duration_millis = 1; - // Camera API level used + // Camera API level used. + // 1 for camera1 API, and 2 for camera2 API. optional int32 api_level = 2; // Name of client package @@ -9967,6 +9970,56 @@ message CameraActionEvent { EXTERNAL = 3; } optional Facing facing = 4; + + // Camera ID + optional string camera_id = 5; + + // Camera action type + enum Action { + UNKNOWN_ACTION = 0; + OPEN = 1; + CLOSE = 2; + SESSION = 3; + } + optional Action action = 6; + + // Whether the client is accessing camera using ndk + optional bool is_ndk = 7; + + // Action OPEN: Open latency + // Action CLOSE: Close latency + // Action SESSION: Camera session creation duration. + // If this entry is reusing an existing session, the value is -1. + optional int32 latency_millis = 8; + + // session type: 0 for normal mode, 1 for constrained high speed mode + optional int32 operating_mode = 9; + + // If actioh is SESSION: number of internal reconfigurations + // Else: 0 + optional int32 internal_reconfig = 10; + + // Number of requests for this capture session. Only applicable to SESSION + // action. + optional int64 request_count = 11; + // Number of result errors. Only applicable to SESSION action. + optional int64 result_error_count = 12; + // Whether the device runs into error state. + optional bool device_error = 13; + + // If action is SESSION: Stream states + // Else: stream_count = 0 + optional int32 stream_count = 14; + optional android.stats.camera.CameraStreamProto stream_1 = 15 + [(android.os.statsd.log_mode) = MODE_BYTES]; + optional android.stats.camera.CameraStreamProto stream_2 = 16 + [(android.os.statsd.log_mode) = MODE_BYTES]; + optional android.stats.camera.CameraStreamProto stream_3 = 17 + [(android.os.statsd.log_mode) = MODE_BYTES]; + optional android.stats.camera.CameraStreamProto stream_4 = 18 + [(android.os.statsd.log_mode) = MODE_BYTES]; + optional android.stats.camera.CameraStreamProto stream_5 = 19 + [(android.os.statsd.log_mode) = MODE_BYTES]; } /** diff --git a/config/preloaded-classes b/config/preloaded-classes index bbdb5e9be99e..8d2f1434b12f 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -6749,6 +6749,7 @@ android.sysprop.-$$Lambda$TelephonyProperties$illdaSIVv8AlxP9uc8NqC3Ta1tA android.sysprop.-$$Lambda$TelephonyProperties$klELuV5zVSqFveC5l6c3FSJmLAU android.sysprop.-$$Lambda$TelephonyProperties$pFU8zg4eHAdooeRLJg1WBG52cKk android.sysprop.-$$Lambda$TelephonyProperties$sXc3eBCFirzHWb9pvClH7EsiM_Q +android.stats.camera.nano.CameraStreamProto android.sysprop.AdbProperties android.sysprop.ApexProperties android.sysprop.ContactsProperties diff --git a/core/java/android/hardware/CameraSessionStats.java b/core/java/android/hardware/CameraSessionStats.java new file mode 100644 index 000000000000..f34e2bf5ddc2 --- /dev/null +++ b/core/java/android/hardware/CameraSessionStats.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; +/** + * The camera action state used for passing camera usage information from + * camera service to camera service proxy . + * + * Include camera id, facing, state, client apk name, apiLevel, isNdk, + * and session/stream statistics. + * + * @hide + */ +public class CameraSessionStats implements Parcelable { + public static final int CAMERA_STATE_OPEN = 0; + public static final int CAMERA_STATE_ACTIVE = 1; + public static final int CAMERA_STATE_IDLE = 2; + public static final int CAMERA_STATE_CLOSED = 3; + + /** + * Values for notifyCameraState facing + */ + public static final int CAMERA_FACING_BACK = 0; + public static final int CAMERA_FACING_FRONT = 1; + public static final int CAMERA_FACING_EXTERNAL = 2; + + /** + * Values for notifyCameraState api level + */ + public static final int CAMERA_API_LEVEL_1 = 1; + public static final int CAMERA_API_LEVEL_2 = 2; + + private String mCameraId; + private int mFacing; + private int mNewCameraState; + private String mClientName; + private int mApiLevel; + private boolean mIsNdk; + private int mLatencyMs; + private int mSessionType; + private int mInternalReconfigure; + private long mRequestCount; + private long mResultErrorCount; + private boolean mDeviceError; + private ArrayList<CameraStreamStats> mStreamStats; + + public CameraSessionStats() { + mFacing = -1; + mNewCameraState = -1; + mApiLevel = -1; + mIsNdk = false; + mLatencyMs = -1; + mSessionType = -1; + mInternalReconfigure = -1; + mRequestCount = 0; + mResultErrorCount = 0; + mDeviceError = false; + mStreamStats = new ArrayList<CameraStreamStats>(); + } + + public CameraSessionStats(String cameraId, int facing, int newCameraState, + String clientName, int apiLevel, boolean isNdk, int creationDuration, + int sessionType, int internalReconfigure) { + mCameraId = cameraId; + mFacing = facing; + mNewCameraState = newCameraState; + mClientName = clientName; + mApiLevel = apiLevel; + mIsNdk = isNdk; + mLatencyMs = creationDuration; + mSessionType = sessionType; + mInternalReconfigure = internalReconfigure; + mStreamStats = new ArrayList<CameraStreamStats>(); + } + + public static final @android.annotation.NonNull Parcelable.Creator<CameraSessionStats> CREATOR = + new Parcelable.Creator<CameraSessionStats>() { + @Override + public CameraSessionStats createFromParcel(Parcel in) { + return new CameraSessionStats(in); + } + + @Override + public CameraSessionStats[] newArray(int size) { + return new CameraSessionStats[size]; + } + }; + + private CameraSessionStats(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mCameraId); + dest.writeInt(mFacing); + dest.writeInt(mNewCameraState); + dest.writeString(mClientName); + dest.writeInt(mApiLevel); + dest.writeBoolean(mIsNdk); + dest.writeInt(mLatencyMs); + dest.writeInt(mSessionType); + dest.writeInt(mInternalReconfigure); + dest.writeLong(mRequestCount); + dest.writeLong(mResultErrorCount); + dest.writeBoolean(mDeviceError); + dest.writeTypedList(mStreamStats); + } + + public void readFromParcel(Parcel in) { + mCameraId = in.readString(); + mFacing = in.readInt(); + mNewCameraState = in.readInt(); + mClientName = in.readString(); + mApiLevel = in.readInt(); + mIsNdk = in.readBoolean(); + mLatencyMs = in.readInt(); + mSessionType = in.readInt(); + mInternalReconfigure = in.readInt(); + mRequestCount = in.readLong(); + mResultErrorCount = in.readLong(); + mDeviceError = in.readBoolean(); + + ArrayList<CameraStreamStats> streamStats = new ArrayList<CameraStreamStats>(); + in.readTypedList(streamStats, CameraStreamStats.CREATOR); + mStreamStats = streamStats; + } + + public String getCameraId() { + return mCameraId; + } + + public int getFacing() { + return mFacing; + } + + public int getNewCameraState() { + return mNewCameraState; + } + + public String getClientName() { + return mClientName; + } + + public int getApiLevel() { + return mApiLevel; + } + + public boolean isNdk() { + return mIsNdk; + } + + public int getLatencyMs() { + return mLatencyMs; + } + + public int getSessionType() { + return mSessionType; + } + + public int getInternalReconfigureCount() { + return mInternalReconfigure; + } + + public long getRequestCount() { + return mRequestCount; + } + + public long getResultErrorCount() { + return mResultErrorCount; + } + + public boolean getDeviceErrorFlag() { + return mDeviceError; + } + + public List<CameraStreamStats> getStreamStats() { + return mStreamStats; + } +} diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java new file mode 100644 index 000000000000..ae801b639d51 --- /dev/null +++ b/core/java/android/hardware/CameraStreamStats.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import java.util.ArrayList; +/** + * The camera stream statistics used for passing camera stream information from + * camera service to camera service proxy. + * + * Include camera stream configuration, request/error counts, startup latency, + * and latency/jitter histograms. + * + * @hide + */ +public class CameraStreamStats implements Parcelable { + + private int mWidth; + private int mHeight; + private int mFormat; + private int mDataSpace; + private long mUsage; + private long mRequestCount; + private long mErrorCount; + private int mStartLatencyMs; + private int mMaxHalBuffers; + private int mMaxAppBuffers; + + private static final String TAG = "CameraStreamStats"; + + public CameraStreamStats() { + mWidth = 0; + mHeight = 0; + mFormat = 0; + mDataSpace = 0; + mUsage = 0; + mRequestCount = 0; + mErrorCount = 0; + mStartLatencyMs = 0; + mMaxHalBuffers = 0; + mMaxAppBuffers = 0; + } + + public CameraStreamStats(int width, int height, int format, + int dataSpace, long usage, long requestCount, long errorCount, + int startLatencyMs, int maxHalBuffers, int maxAppBuffers) { + mWidth = width; + mHeight = height; + mFormat = format; + mDataSpace = dataSpace; + mUsage = usage; + mRequestCount = requestCount; + mErrorCount = errorCount; + mStartLatencyMs = startLatencyMs; + mMaxHalBuffers = maxHalBuffers; + mMaxAppBuffers = maxAppBuffers; + } + + public static final @android.annotation.NonNull Parcelable.Creator<CameraStreamStats> CREATOR = + new Parcelable.Creator<CameraStreamStats>() { + @Override + public CameraStreamStats createFromParcel(Parcel in) { + try { + CameraStreamStats streamStats = new CameraStreamStats(in); + return streamStats; + } catch (Exception e) { + Log.e(TAG, "Exception creating CameraStreamStats from parcel", e); + return null; + } + } + + @Override + public CameraStreamStats[] newArray(int size) { + return new CameraStreamStats[size]; + } + }; + + private CameraStreamStats(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mWidth); + dest.writeInt(mHeight); + dest.writeInt(mFormat); + dest.writeInt(mDataSpace); + dest.writeLong(mUsage); + dest.writeLong(mRequestCount); + dest.writeLong(mErrorCount); + dest.writeInt(mStartLatencyMs); + dest.writeInt(mMaxHalBuffers); + dest.writeInt(mMaxAppBuffers); + } + + public void readFromParcel(Parcel in) { + mWidth = in.readInt(); + mHeight = in.readInt(); + mFormat = in.readInt(); + mDataSpace = in.readInt(); + mUsage = in.readLong(); + mRequestCount = in.readLong(); + mErrorCount = in.readLong(); + mStartLatencyMs = in.readInt(); + mMaxHalBuffers = in.readInt(); + mMaxAppBuffers = in.readInt(); + } + + public int getWidth() { + return mWidth; + } + + public int getHeight() { + return mHeight; + } + + public int getFormat() { + return mFormat; + } + + public int getDataSpace() { + return mDataSpace; + } + + public long getUsage() { + return mUsage; + } + + public long getRequestCount() { + return mRequestCount; + } + + public long getErrorCount() { + return mErrorCount; + } + + public int getStartLatencyMs() { + return mStartLatencyMs; + } + + public int getMaxHalBuffers() { + return mMaxHalBuffers; + } + + public int getMaxAppBuffers() { + return mMaxAppBuffers; + } +} diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index b6f4bd3c4c28..9a9163c724ff 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -27,6 +27,7 @@ import android.hardware.camera2.utils.TaskDrainer; import android.hardware.camera2.utils.TaskSingleDrainer; import android.os.Binder; import android.os.Handler; +import android.os.SystemClock; import android.util.Log; import android.view.Surface; @@ -1002,7 +1003,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession // begin transition to unconfigured mDeviceImpl.configureStreamsChecked(/*inputConfig*/null, /*outputs*/null, /*operatingMode*/ ICameraDeviceUser.NORMAL_MODE, - /*sessionParams*/ null); + /*sessionParams*/ null, SystemClock.uptimeMillis()); } catch (CameraAccessException e) { // OK: do not throw checked exceptions. Log.e(TAG, mIdString + "Exception while unconfiguring outputs: ", e); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 819d966e3bfe..f564ad7436de 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -45,6 +45,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceSpecificException; +import android.os.SystemClock; import android.util.Log; import android.util.Range; import android.util.Size; @@ -374,7 +375,8 @@ public class CameraDeviceImpl extends CameraDevice outputConfigs.add(new OutputConfiguration(s)); } configureStreamsChecked(/*inputConfig*/null, outputConfigs, - /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null); + /*operatingMode*/ICameraDeviceUser.NORMAL_MODE, /*sessionParams*/ null, + SystemClock.uptimeMillis()); } @@ -395,12 +397,15 @@ public class CameraDeviceImpl extends CameraDevice * @param operatingMode If the stream configuration is for a normal session, * a constrained high speed session, or something else. * @param sessionParams Session parameters. + * @param createSessionStartTimeMs The timestamp when session creation starts, measured by + * uptimeMillis(). * @return whether or not the configuration was successful * * @throws CameraAccessException if there were any unexpected problems during configuration */ public boolean configureStreamsChecked(InputConfiguration inputConfig, - List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams) + List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams, + long createSessionStartTime) throws CameraAccessException { // Treat a null input the same an empty list if (outputs == null) { @@ -479,9 +484,10 @@ public class CameraDeviceImpl extends CameraDevice int offlineStreamIds[]; if (sessionParams != null) { offlineStreamIds = mRemoteDevice.endConfigure(operatingMode, - sessionParams.getNativeCopy()); + sessionParams.getNativeCopy(), createSessionStartTime); } else { - offlineStreamIds = mRemoteDevice.endConfigure(operatingMode, null); + offlineStreamIds = mRemoteDevice.endConfigure(operatingMode, null, + createSessionStartTime); } mOfflineSupport.clear(); @@ -650,6 +656,7 @@ public class CameraDeviceImpl extends CameraDevice List<OutputConfiguration> outputConfigurations, CameraCaptureSession.StateCallback callback, Executor executor, int operatingMode, CaptureRequest sessionParams) throws CameraAccessException { + long createSessionStartTime = SystemClock.uptimeMillis(); synchronized(mInterfaceLock) { if (DEBUG) { Log.d(TAG, "createCaptureSessionInternal"); @@ -677,7 +684,7 @@ public class CameraDeviceImpl extends CameraDevice try { // configure streams and then block until IDLE configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations, - operatingMode, sessionParams); + operatingMode, sessionParams, createSessionStartTime); if (configureSuccess == true && inputConfig != null) { input = mRemoteDevice.getInputSurface(); } diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java index fa7301bb72c3..ba4395f70214 100644 --- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java +++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java @@ -110,11 +110,11 @@ public class ICameraDeviceUserWrapper { } } - public int[] endConfigure(int operatingMode, CameraMetadataNative sessionParams) - throws CameraAccessException { + public int[] endConfigure(int operatingMode, CameraMetadataNative sessionParams, + long startTimeMs) throws CameraAccessException { try { return mRemoteDevice.endConfigure(operatingMode, (sessionParams == null) ? - new CameraMetadataNative() : sessionParams); + new CameraMetadataNative() : sessionParams, startTimeMs); } catch (Throwable t) { CameraManager.throwAsPublicException(t); throw new UnsupportedOperationException("Unexpected exception", t); diff --git a/core/proto/android/stats/camera/Android.bp b/core/proto/android/stats/camera/Android.bp new file mode 100644 index 000000000000..cc75e57af87b --- /dev/null +++ b/core/proto/android/stats/camera/Android.bp @@ -0,0 +1,33 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +java_library { + name: "cameraprotosnano", + proto: { + type: "nano", + }, + srcs: [ + "*.proto", + ], + java_version: "1.8", + target: { + android: { + jarjar_rules: "jarjar-rules.txt", + }, + host: { + static_libs: ["libprotobuf-java-nano"], + } + }, + sdk_version: "core_platform", +} diff --git a/core/proto/android/stats/camera/camera.proto b/core/proto/android/stats/camera/camera.proto new file mode 100644 index 000000000000..406285551d98 --- /dev/null +++ b/core/proto/android/stats/camera/camera.proto @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +package android.stats.camera; +option java_multiple_files = true; + +message CameraStreamProto { + // The stream width (in pixels) + optional int32 width = 1; + // The stream height (in pixels) + optional int32 height = 2; + // The format of the stream + optional int32 format = 3; + // The dataspace of the stream + optional int32 data_space = 4; + // The usage flag of the stream + optional int64 usage = 5; + + // The number of requests for this stream + optional int64 request_count = 6; + // The number of buffer error for this stream + optional int64 error_count = 7; + // The capture latency of first request for this stream + optional int32 first_capture_latency_millis = 8; + + // The maximum number of hal buffers + optional int32 max_hal_buffers = 9; + // The maximum number of app buffers + optional int32 max_app_buffers = 10; +} diff --git a/core/proto/android/stats/camera/jarjar-rules.txt b/core/proto/android/stats/camera/jarjar-rules.txt new file mode 100644 index 000000000000..40043a861ceb --- /dev/null +++ b/core/proto/android/stats/camera/jarjar-rules.txt @@ -0,0 +1 @@ +rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1 diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index a4ae9c87c694..2a814268da25 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -22,6 +22,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.hardware.CameraSessionStats; +import android.hardware.CameraStreamStats; import android.hardware.ICameraService; import android.hardware.ICameraServiceProxy; import android.media.AudioManager; @@ -36,11 +38,13 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserManager; +import android.stats.camera.nano.CameraStreamProto; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.framework.protobuf.nano.MessageNano; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.FrameworkStatsLog; @@ -97,7 +101,10 @@ public class CameraServiceProxy extends SystemService @interface DeviceStateFlags {} // Maximum entries to keep in usage history before dumping out - private static final int MAX_USAGE_HISTORY = 100; + private static final int MAX_USAGE_HISTORY = 20; + // Number of stream statistics being dumped for each camera session + // Must be equal to number of CameraStreamProto in CameraActionEvent + private static final int MAX_STREAM_STATISTICS = 5; private final Context mContext; private final ServiceThread mHandlerThread; @@ -123,7 +130,6 @@ public class CameraServiceProxy extends SystemService private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>(); private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>(); - private final MetricsLogger mLogger = new MetricsLogger(); private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc"; private static final String NFC_SERVICE_BINDER_NAME = "nfc"; private static final IBinder nfcInterfaceToken = new Binder(); @@ -137,27 +143,50 @@ public class CameraServiceProxy extends SystemService * Structure to track camera usage */ private static class CameraUsageEvent { + public final String mCameraId; public final int mCameraFacing; public final String mClientName; public final int mAPILevel; + public final boolean mIsNdk; + public final int mAction; + public final int mLatencyMs; + public final int mOperatingMode; private boolean mCompleted; + public int mInternalReconfigure; + public long mRequestCount; + public long mResultErrorCount; + public boolean mDeviceError; + public List<CameraStreamStats> mStreamStats; private long mDurationOrStartTimeMs; // Either start time, or duration once completed - public CameraUsageEvent(int facing, String clientName, int apiLevel) { + CameraUsageEvent(String cameraId, int facing, String clientName, int apiLevel, + boolean isNdk, int action, int latencyMs, int operatingMode) { + mCameraId = cameraId; mCameraFacing = facing; mClientName = clientName; mAPILevel = apiLevel; mDurationOrStartTimeMs = SystemClock.elapsedRealtime(); mCompleted = false; + mIsNdk = isNdk; + mAction = action; + mLatencyMs = latencyMs; + mOperatingMode = operatingMode; } - public void markCompleted() { + public void markCompleted(int internalReconfigure, long requestCount, + long resultErrorCount, boolean deviceError, + List<CameraStreamStats> streamStats) { if (mCompleted) { return; } mCompleted = true; mDurationOrStartTimeMs = SystemClock.elapsedRealtime() - mDurationOrStartTimeMs; + mInternalReconfigure = internalReconfigure; + mRequestCount = requestCount; + mResultErrorCount = resultErrorCount; + mDeviceError = deviceError; + mStreamStats = streamStats; if (CameraServiceProxy.DEBUG) { Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) + " was in use by " + mClientName + " for " + @@ -211,19 +240,22 @@ public class CameraServiceProxy extends SystemService } @Override - public void notifyCameraState(String cameraId, int newCameraState, int facing, - String clientName, int apiLevel) { + public void notifyCameraState(CameraSessionStats cameraState) { if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " + " camera service UID!"); return; } - String state = cameraStateToString(newCameraState); - String facingStr = cameraFacingToString(facing); - if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " + - state + " for client " + clientName + " API Level " + apiLevel); + String state = cameraStateToString(cameraState.getNewCameraState()); + String facingStr = cameraFacingToString(cameraState.getFacing()); + if (DEBUG) { + Slog.v(TAG, "Camera " + cameraState.getCameraId() + + " facing " + facingStr + " state now " + state + + " for client " + cameraState.getClientName() + + " API Level " + cameraState.getApiLevel()); + } - updateActivityCount(cameraId, newCameraState, facing, clientName, apiLevel); + updateActivityCount(cameraState); } }; @@ -385,20 +417,80 @@ public class CameraServiceProxy extends SystemService private void logCameraUsageEvent(CameraUsageEvent e) { int facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN; switch(e.mCameraFacing) { - case ICameraServiceProxy.CAMERA_FACING_BACK: + case CameraSessionStats.CAMERA_FACING_BACK: facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__BACK; break; - case ICameraServiceProxy.CAMERA_FACING_FRONT: + case CameraSessionStats.CAMERA_FACING_FRONT: facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__FRONT; break; - case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: + case CameraSessionStats.CAMERA_FACING_EXTERNAL: facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL; break; default: Slog.w(TAG, "Unknown camera facing: " + e.mCameraFacing); } + + int streamCount = 0; + if (e.mStreamStats != null) { + streamCount = e.mStreamStats.size(); + } + if (CameraServiceProxy.DEBUG) { + Slog.v(TAG, "CAMERA_ACTION_EVENT: action " + e.mAction + + " clientName " + e.mClientName + + ", duration " + e.getDuration() + + ", APILevel " + e.mAPILevel + + ", cameraId " + e.mCameraId + + ", facing " + facing + + ", isNdk " + e.mIsNdk + + ", latencyMs " + e.mLatencyMs + + ", operatingMode " + e.mOperatingMode + + ", internalReconfigure " + e.mInternalReconfigure + + ", requestCount " + e.mRequestCount + + ", resultErrorCount " + e.mResultErrorCount + + ", deviceError " + e.mDeviceError + + ", streamCount is " + streamCount); + } + // Convert from CameraStreamStats to CameraStreamProto + CameraStreamProto[] streamProtos = new CameraStreamProto[MAX_STREAM_STATISTICS]; + for (int i = 0; i < MAX_STREAM_STATISTICS; i++) { + streamProtos[i] = new CameraStreamProto(); + if (i < streamCount) { + CameraStreamStats streamStats = e.mStreamStats.get(i); + streamProtos[i].width = streamStats.getWidth(); + streamProtos[i].height = streamStats.getHeight(); + streamProtos[i].format = streamStats.getFormat(); + streamProtos[i].dataSpace = streamStats.getDataSpace(); + streamProtos[i].usage = streamStats.getUsage(); + streamProtos[i].requestCount = streamStats.getRequestCount(); + streamProtos[i].errorCount = streamStats.getErrorCount(); + streamProtos[i].firstCaptureLatencyMillis = streamStats.getStartLatencyMs(); + streamProtos[i].maxHalBuffers = streamStats.getMaxHalBuffers(); + streamProtos[i].maxAppBuffers = streamStats.getMaxAppBuffers(); + + if (CameraServiceProxy.DEBUG) { + Slog.v(TAG, "Stream " + i + ": width " + streamProtos[i].width + + ", height " + streamProtos[i].height + + ", format " + streamProtos[i].format + + ", dataSpace " + streamProtos[i].dataSpace + + ", usage " + streamProtos[i].usage + + ", requestCount " + streamProtos[i].requestCount + + ", errorCount " + streamProtos[i].errorCount + + ", firstCaptureLatencyMillis " + + streamProtos[i].firstCaptureLatencyMillis + + ", maxHalBuffers " + streamProtos[i].maxHalBuffers + + ", maxAppBuffers " + streamProtos[i].maxAppBuffers); + } + } + } FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_ACTION_EVENT, e.getDuration(), - e.mAPILevel, e.mClientName, facing); + e.mAPILevel, e.mClientName, facing, e.mCameraId, e.mAction, e.mIsNdk, + e.mLatencyMs, e.mOperatingMode, e.mInternalReconfigure, + e.mRequestCount, e.mResultErrorCount, e.mDeviceError, + streamCount, MessageNano.toByteArray(streamProtos[0]), + MessageNano.toByteArray(streamProtos[1]), + MessageNano.toByteArray(streamProtos[2]), + MessageNano.toByteArray(streamProtos[3]), + MessageNano.toByteArray(streamProtos[4])); } } @@ -410,35 +502,6 @@ public class CameraServiceProxy extends SystemService synchronized(mLock) { // Randomize order of events so that it's not meaningful Collections.shuffle(mCameraUsageHistory); - for (CameraUsageEvent e : mCameraUsageHistory) { - if (DEBUG) { - Slog.v(TAG, "Camera: " + e.mClientName + " used a camera facing " + - cameraFacingToString(e.mCameraFacing) + " for " + - e.getDuration() + " ms"); - } - int subtype = 0; - switch(e.mCameraFacing) { - case ICameraServiceProxy.CAMERA_FACING_BACK: - subtype = MetricsEvent.CAMERA_BACK_USED; - break; - case ICameraServiceProxy.CAMERA_FACING_FRONT: - subtype = MetricsEvent.CAMERA_FRONT_USED; - break; - case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: - subtype = MetricsEvent.CAMERA_EXTERNAL_USED; - break; - default: - continue; - } - LogMaker l = new LogMaker(MetricsEvent.ACTION_CAMERA_EVENT) - .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(subtype) - .setLatency(e.getDuration()) - .addTaggedData(MetricsEvent.FIELD_CAMERA_API_LEVEL, e.mAPILevel) - .setPackageName(e.mClientName); - mLogger.write(l); - } - mLogWriterService.execute(new EventWriterTask( new ArrayList<CameraUsageEvent>(mCameraUsageHistory))); @@ -569,13 +632,25 @@ public class CameraServiceProxy extends SystemService return true; } - private void updateActivityCount(String cameraId, int newCameraState, int facing, - String clientName, int apiLevel) { + private void updateActivityCount(CameraSessionStats cameraState) { + String cameraId = cameraState.getCameraId(); + int newCameraState = cameraState.getNewCameraState(); + int facing = cameraState.getFacing(); + String clientName = cameraState.getClientName(); + int apiLevel = cameraState.getApiLevel(); + boolean isNdk = cameraState.isNdk(); + int sessionType = cameraState.getSessionType(); + int internalReconfigureCount = cameraState.getInternalReconfigureCount(); + int latencyMs = cameraState.getLatencyMs(); + long requestCount = cameraState.getRequestCount(); + long resultErrorCount = cameraState.getResultErrorCount(); + boolean deviceError = cameraState.getDeviceErrorFlag(); + List<CameraStreamStats> streamStats = cameraState.getStreamStats(); synchronized(mLock) { // Update active camera list and notify NFC if necessary boolean wasEmpty = mActiveCameraUsage.isEmpty(); switch (newCameraState) { - case ICameraServiceProxy.CAMERA_STATE_OPEN: + case CameraSessionStats.CAMERA_STATE_OPEN: // Notify the audio subsystem about the facing of the most-recently opened // camera This can be used to select the best audio tuning in case video // recording with that camera will happen. Since only open events are used, if @@ -584,13 +659,18 @@ public class CameraServiceProxy extends SystemService AudioManager audioManager = getContext().getSystemService(AudioManager.class); if (audioManager != null) { // Map external to front for audio tuning purposes - String facingStr = (facing == ICameraServiceProxy.CAMERA_FACING_BACK) ? + String facingStr = (facing == CameraSessionStats.CAMERA_FACING_BACK) ? "back" : "front"; String facingParameter = "cameraFacing=" + facingStr; audioManager.setParameters(facingParameter); } + CameraUsageEvent openEvent = new CameraUsageEvent( + cameraId, facing, clientName, apiLevel, isNdk, + FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__OPEN, + latencyMs, sessionType); + mCameraUsageHistory.add(openEvent); break; - case ICameraServiceProxy.CAMERA_STATE_ACTIVE: + case CameraSessionStats.CAMERA_STATE_ACTIVE: // Check current active camera IDs to see if this package is already talking to // some camera boolean alreadyActivePackage = false; @@ -609,40 +689,55 @@ public class CameraServiceProxy extends SystemService } // Update activity events - CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel); + CameraUsageEvent newEvent = new CameraUsageEvent( + cameraId, facing, clientName, apiLevel, isNdk, + FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__SESSION, + latencyMs, sessionType); CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent); if (oldEvent != null) { Slog.w(TAG, "Camera " + cameraId + " was already marked as active"); - oldEvent.markCompleted(); + oldEvent.markCompleted(/*internalReconfigure*/0, /*requestCount*/0, + /*resultErrorCount*/0, /*deviceError*/false, streamStats); mCameraUsageHistory.add(oldEvent); } break; - case ICameraServiceProxy.CAMERA_STATE_IDLE: - case ICameraServiceProxy.CAMERA_STATE_CLOSED: + case CameraSessionStats.CAMERA_STATE_IDLE: + case CameraSessionStats.CAMERA_STATE_CLOSED: CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId); - if (doneEvent == null) break; - - doneEvent.markCompleted(); - mCameraUsageHistory.add(doneEvent); - if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) { - dumpUsageEvents(); + if (doneEvent != null) { + + doneEvent.markCompleted(internalReconfigureCount, requestCount, + resultErrorCount, deviceError, streamStats); + mCameraUsageHistory.add(doneEvent); + + // Check current active camera IDs to see if this package is still + // talking to some camera + boolean stillActivePackage = false; + for (int i = 0; i < mActiveCameraUsage.size(); i++) { + if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) { + stillActivePackage = true; + break; + } + } + // If not longer active, notify window manager about this package being done + // with camera + if (!stillActivePackage) { + WindowManagerInternal wmi = + LocalServices.getService(WindowManagerInternal.class); + wmi.removeNonHighRefreshRatePackage(clientName); + } } - // Check current active camera IDs to see if this package is still talking to - // some camera - boolean stillActivePackage = false; - for (int i = 0; i < mActiveCameraUsage.size(); i++) { - if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) { - stillActivePackage = true; - break; - } + if (newCameraState == CameraSessionStats.CAMERA_STATE_CLOSED) { + CameraUsageEvent closeEvent = new CameraUsageEvent( + cameraId, facing, clientName, apiLevel, isNdk, + FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__CLOSE, + latencyMs, sessionType); + mCameraUsageHistory.add(closeEvent); } - // If not longer active, notify window manager about this package being done - // with camera - if (!stillActivePackage) { - WindowManagerInternal wmi = - LocalServices.getService(WindowManagerInternal.class); - wmi.removeNonHighRefreshRatePackage(clientName); + + if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) { + dumpUsageEvents(); } break; @@ -683,10 +778,10 @@ public class CameraServiceProxy extends SystemService private static String cameraStateToString(int newCameraState) { switch (newCameraState) { - case ICameraServiceProxy.CAMERA_STATE_OPEN: return "CAMERA_STATE_OPEN"; - case ICameraServiceProxy.CAMERA_STATE_ACTIVE: return "CAMERA_STATE_ACTIVE"; - case ICameraServiceProxy.CAMERA_STATE_IDLE: return "CAMERA_STATE_IDLE"; - case ICameraServiceProxy.CAMERA_STATE_CLOSED: return "CAMERA_STATE_CLOSED"; + case CameraSessionStats.CAMERA_STATE_OPEN: return "CAMERA_STATE_OPEN"; + case CameraSessionStats.CAMERA_STATE_ACTIVE: return "CAMERA_STATE_ACTIVE"; + case CameraSessionStats.CAMERA_STATE_IDLE: return "CAMERA_STATE_IDLE"; + case CameraSessionStats.CAMERA_STATE_CLOSED: return "CAMERA_STATE_CLOSED"; default: break; } return "CAMERA_STATE_UNKNOWN"; @@ -694,9 +789,9 @@ public class CameraServiceProxy extends SystemService private static String cameraFacingToString(int cameraFacing) { switch (cameraFacing) { - case ICameraServiceProxy.CAMERA_FACING_BACK: return "CAMERA_FACING_BACK"; - case ICameraServiceProxy.CAMERA_FACING_FRONT: return "CAMERA_FACING_FRONT"; - case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: return "CAMERA_FACING_EXTERNAL"; + case CameraSessionStats.CAMERA_FACING_BACK: return "CAMERA_FACING_BACK"; + case CameraSessionStats.CAMERA_FACING_FRONT: return "CAMERA_FACING_FRONT"; + case CameraSessionStats.CAMERA_FACING_EXTERNAL: return "CAMERA_FACING_EXTERNAL"; default: break; } return "CAMERA_FACING_UNKNOWN"; |