Merge "Camera: Enhance camera atoms for system health"

This commit is contained in:
TreeHugger Robot
2020-11-19 18:22:50 +00:00
committed by Android (Google) Code Review
12 changed files with 697 additions and 90 deletions

View File

@@ -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",

View File

@@ -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];
}
/**

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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",
}

View File

@@ -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;
}

View File

@@ -0,0 +1 @@
rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1

View File

@@ -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;
if (doneEvent != null) {
doneEvent.markCompleted();
mCameraUsageHistory.add(doneEvent);
if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) {
dumpUsageEvents();
}
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;
// 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);
}
}
// 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 (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 (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";